mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-03-11 17:15:38 +00:00
Merge
This commit is contained in:
commit
a60b046eb2
9 changed files with 430 additions and 35 deletions
2
dist/BlueMarble.user.css
vendored
2
dist/BlueMarble.user.css
vendored
|
|
@ -1 +1 @@
|
|||
#bm-l{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000}div#bm-l{font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-g{margin-bottom:.5em;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="5" height="5"><circle cx="3" cy="3" r="1.5" fill="CornflowerBlue" /></svg>') repeat;cursor:grab;width:100%;height:1em}#bm-g.dragging{cursor:grabbing}#bm-7{margin-bottom:.5em}#bm-l img{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}#bm-l h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}#bm-3 input[type=checkbox]{vertical-align:middle;margin-right:.5ch}#bm-3 label{margin-right:.5ch}.bm-p{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}#bm-c{vertical-align:middle}#bm-c svg{width:50%;margin:0 auto;fill:#111}div:has(>#bm-button-teleport){display:flex;gap:.5ch}#bm-button-favorite svg,#bm-button-template svg{height:1em;margin:2px auto 0;text-align:center;line-height:1em;vertical-align:bottom}#bm-8 input[type=number]{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}#bm-8 input[type=number]::-webkit-outer-spin-button,#bm-8 input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}#bm-0{display:flex;flex-direction:row;flex-wrap:wrap;align-content:center;justify-content:center;align-items:center;gap:1ch}div:has(>#bm-2)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#bm-a{font-size:small;background-color:#0003;padding:0 .5ch;height:3.75em;width:100%}#bm-1{display:flex;justify-content:space-between}#bm-l small{font-size:x-small;color:#d3d3d3}#bm-4,#bm-3,#bm-8,#bm-0,div:has(>#bm-2),#bm-a{margin-top:.5em}#bm-l button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}#bm-l button:hover,#bm-l button:focus-visible{background-color:#1061e5}#bm-l button:active,#bm-l button:disabled{background-color:#2e97ff}#bm-l button:disabled{text-decoration:line-through}
|
||||
#bm-l{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease;max-width:300px;width:auto}#bm-4,#bm-l hr,#bm-3,#bm-1{transition:opacity .2s ease,height .2s ease}div#bm-l{font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-g{margin-bottom:.5em;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="5" height="5"><circle cx="3" cy="3" r="1.5" fill="CornflowerBlue" /></svg>') repeat;cursor:grab;width:100%;height:1em}#bm-g.dragging{cursor:grabbing}#bm-7{margin-bottom:.5em}#bm-7[style*="text-align: center"]{display:flex;flex-direction:column;align-items:center;justify-content:center}#bm-l[style*="padding: 5px"]{width:auto!important;max-width:300px;min-width:200px}#bm-l img{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle;transition:opacity .2s ease}#bm-7[style*="text-align: center"] img{display:block;margin:0 auto}#bm-g{transition:margin-bottom .2s ease}#bm-l h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}#bm-3 input[type=checkbox]{vertical-align:middle;margin-right:.5ch}#bm-3 label{margin-right:.5ch}.bm-p{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}#bm-c{vertical-align:middle}#bm-c svg{width:50%;margin:0 auto;fill:#111}div:has(>#bm-button-teleport){display:flex;gap:.5ch}#bm-button-favorite svg,#bm-button-template svg{height:1em;margin:2px auto 0;text-align:center;line-height:1em;vertical-align:bottom}#bm-8 input[type=number]{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}#bm-8 input[type=number]::-webkit-outer-spin-button,#bm-8 input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}#bm-0{display:flex;flex-direction:row;flex-wrap:wrap;align-content:center;justify-content:center;align-items:center;gap:1ch}div:has(>#bm-2)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#bm-a{font-size:small;background-color:#0003;padding:0 .5ch;height:3.75em;width:100%}#bm-1{display:flex;justify-content:space-between}#bm-l small{font-size:x-small;color:#d3d3d3}#bm-4,#bm-3,#bm-8,#bm-0,div:has(>#bm-2),#bm-a{margin-top:.5em}#bm-l button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}#bm-l button:hover,#bm-l button:focus-visible{background-color:#1061e5}#bm-l button:active,#bm-l button:disabled{background-color:#2e97ff}#bm-l button:disabled{text-decoration:line-through}
|
||||
|
|
|
|||
8
dist/BlueMarble.user.js
vendored
8
dist/BlueMarble.user.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -39,7 +39,7 @@
|
|||
</table>
|
||||
|
||||
<h1>Blue Marble</h1>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Latest Version" src="https://img.shields.io/badge/Latest_Version-0.70.0-lightblue?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Latest Version" src="https://img.shields.io/badge/Latest_Version-0.71.0-lightblue?style=flat"></a>
|
||||
<a href="https://github.com/SwingTheVine/Wplace-BlueMarble/releases" target="_blank" rel="noopener noreferrer"><img alt="Latest Release" src="https://img.shields.io/github/v/release/SwingTheVine/Wplace-BlueMarble?sort=semver&style=flat&label=Latest%20Release&color=blue"></a>
|
||||
<a href="https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/LICENSE.txt" target="_blank" rel="noopener noreferrer"><img alt="Software License: MPL-2.0" src="https://img.shields.io/badge/Software_License-MPL--2.0-slateblue?style=flat"></a>
|
||||
<a href="https://discord.gg/tpeBPy46hf" target="_blank" rel="noopener noreferrer"><img alt="Contact Me" src="https://img.shields.io/badge/Contact_Me-gray?style=flat&logo=Discord&logoColor=white&logoSize=auto&labelColor=cornflowerblue"></a>
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-455-black?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Lines of Code" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=code"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Comments" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=comments"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Compression" src="https://img.shields.io/badge/Compression-73.11%25-blue"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Compression" src="https://img.shields.io/badge/Compression-76.02%25-blue"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Build" src="https://github.com/SwingTheVine/Wplace-BlueMarble/actions/workflows/build.yml/badge.svg"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="CodeQL" src="https://github.com/SwingTheVine/Wplace-BlueMarble/actions/workflows/github-code-scanning/codeql/badge.svg"></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.70.4",
|
||||
"version": "0.71.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node build/build.js",
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
// ==UserScript==
|
||||
// @name Blue Marble
|
||||
// @namespace https://github.com/SwingTheVine/
|
||||
// @version 0.70.4
|
||||
// @version 0.71.0
|
||||
// @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA.
|
||||
// @author SwingTheVine
|
||||
// @license MPL-2.0
|
||||
// @supportURL https://discord.gg/tpeBPy46hf
|
||||
// @homepageURL https://github.com/SwingTheVine/Wplace-BlueMarble
|
||||
// @icon https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/45a9098bedf5a13db39e398db5ac0c3a68eb675d/dist/assets/Favicon.png
|
||||
// @icon https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/a3ff8840069a733d4cf4c27b8336beddf3706b60/dist/assets/Favicon.png
|
||||
// @updateURL https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/BlueMarble.user.js
|
||||
// @downloadURL https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/BlueMarble.user.js
|
||||
// @run-at document-start
|
||||
// @match *://*.wplace.live/*
|
||||
// @grant GM_getResourceText
|
||||
// @grant GM_addStyle
|
||||
// @resource CSS-BM-File https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/45a9098bedf5a13db39e398db5ac0c3a68eb675d/dist/BlueMarble.user.css
|
||||
// @resource CSS-BM-File https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/a3ff8840069a733d4cf4c27b8336beddf3706b60/dist/BlueMarble.user.css
|
||||
// ==/UserScript==
|
||||
|
||||
// Wplace --> https://wplace.live
|
||||
|
|
|
|||
|
|
@ -1,18 +1,47 @@
|
|||
/** An instance of a template.
|
||||
* Handles all mathmatics and manipulation regarding a single template.
|
||||
/** An instance of a template with comprehensive pixel counting and statistics.
|
||||
* Handles all mathematics, manipulation, and statistical analysis regarding a single template.
|
||||
*
|
||||
* TEMPLATE FEATURES:
|
||||
* - Automatic pixel counting and dimension analysis
|
||||
* - Tile-based template chunking for efficient rendering
|
||||
* - Statistical information storage and retrieval
|
||||
* - Bitmap processing with configurable scaling
|
||||
* - Memory-efficient template tile generation
|
||||
*
|
||||
* PIXEL COUNTING SYSTEM:
|
||||
* - Calculates total pixel count (width × height) during template creation
|
||||
* - Stores pixel count for statistical display and analysis
|
||||
* - Integrates with template manager for aggregate statistics
|
||||
* - Provides formatted pixel count information to user interface
|
||||
*
|
||||
* @since 0.65.2
|
||||
*/
|
||||
export default class Template {
|
||||
/** The constructor for the {@link Template} class.
|
||||
* @param {Object} [params={}] - Object containing all optional params
|
||||
/** The constructor for the {@link Template} class with enhanced pixel tracking.
|
||||
*
|
||||
* Initializes a new template instance with all necessary properties for rendering
|
||||
* and statistical analysis. The pixel counting system is initialized here and
|
||||
* populated during the template creation process.
|
||||
*
|
||||
* PIXEL COUNTING INTEGRATION:
|
||||
* The pixelCount property is automatically calculated during createTemplateTiles()
|
||||
* and represents the total number of pixels in the source image (width × height).
|
||||
* This information is used for:
|
||||
* - User interface statistics display
|
||||
* - Template comparison and analysis
|
||||
* - Performance optimization decisions
|
||||
* - Memory usage estimation
|
||||
*
|
||||
* @param {Object} [params={}] - Object containing all optional parameters
|
||||
* @param {string} [params.displayName='My template'] - The display name of the template
|
||||
* @param {number} [params.sortID=0] - The sort number of the template
|
||||
* @param {string} [params.authorID=''] - The user ID of the person who exported the template. This is to prevent sort ID collisions when importing
|
||||
* @param {string} [params.url=''] - The URL to the image
|
||||
* @param {File} [params.file=null] - The template file. This can be a pre-processed File, or a processed bitmap
|
||||
* @param {[number, number, number, number]} [params.coords=null] - The coordinates of the top left corner as (x, y, x, y)
|
||||
* @param {number} [params.sortID=0] - The sort number of the template for rendering priority
|
||||
* @param {string} [params.authorID=''] - The user ID of the person who exported the template (prevents sort ID collisions)
|
||||
* @param {string} [params.url=''] - The URL to the source image
|
||||
* @param {File} [params.file=null] - The template file (pre-processed File or processed bitmap)
|
||||
* @param {[number, number, number, number]} [params.coords=null] - The coordinates of the top left corner as (tileX, tileY, pixelX, pixelY)
|
||||
* @param {Object} [params.chunked=null] - The affected chunks of the template, and their template for each chunk
|
||||
* @param {number} [params.tileSize=1000] - The size of a tile in pixels. Assumes the tile is a square
|
||||
* @param {number} [params.tileSize=1000] - The size of a tile in pixels (assumes square tiles)
|
||||
* @param {number} [params.pixelCount=0] - Total number of pixels in the template (calculated automatically during processing)
|
||||
* @since 0.65.2
|
||||
*/
|
||||
constructor({
|
||||
|
|
@ -33,19 +62,59 @@ export default class Template {
|
|||
this.coords = coords;
|
||||
this.chunked = chunked;
|
||||
this.tileSize = tileSize;
|
||||
this.pixelCount = 0; // Total pixel count in template (automatically calculated during createTemplateTiles)
|
||||
}
|
||||
|
||||
/** Creates chunks of the template for each tile.
|
||||
* @returns {Object} Collection of template bitmaps in a Object
|
||||
/** Creates chunks of the template for each tile with integrated pixel counting system.
|
||||
*
|
||||
* This method processes the template image and performs several critical operations:
|
||||
* 1. PIXEL ANALYSIS: Calculates total pixel count (width × height) for statistical purposes
|
||||
* 2. TILE CHUNKING: Divides the template into tile-sized chunks for efficient rendering
|
||||
* 3. BITMAP PROCESSING: Applies scaling and filtering for optimal display quality
|
||||
* 4. MEMORY OPTIMIZATION: Creates efficient ImageBitmap objects for each tile segment
|
||||
*
|
||||
* PIXEL COUNTING IMPLEMENTATION:
|
||||
* The pixel counting system calculates the total number of pixels in the source image
|
||||
* by multiplying the bitmap width by height. This information is stored in the
|
||||
* pixelCount property and used throughout the application for:
|
||||
* - User interface statistics display
|
||||
* - Template comparison and analysis
|
||||
* - Performance monitoring and optimization
|
||||
* - Memory usage estimation and management
|
||||
*
|
||||
* TECHNICAL DETAILS:
|
||||
* - Uses createImageBitmap() for efficient image processing
|
||||
* - Applies 3x scaling factor (shreadSize) for pixel art enhancement
|
||||
* - Processes images in tile-sized chunks for memory efficiency
|
||||
* - Maintains pixel-perfect rendering with nearest-neighbor sampling
|
||||
* - Handles coordinate transformation between template and tile coordinate systems
|
||||
*
|
||||
* PERFORMANCE CONSIDERATIONS:
|
||||
* - Large templates are processed incrementally to avoid memory issues
|
||||
* - Bitmap creation uses OffscreenCanvas for optimal performance
|
||||
* - Pixel counting is performed once during initial processing
|
||||
* - Results are cached in the pixelCount property for repeated access
|
||||
*
|
||||
* @returns {Object} Collection of template bitmaps organized by tile coordinates
|
||||
* @since 0.65.4
|
||||
*/
|
||||
async createTemplateTiles() {
|
||||
console.log(this.coords);
|
||||
console.log('Template coordinates:', this.coords);
|
||||
|
||||
const shreadSize = 3; // Scale image factor. Must be odd
|
||||
const bitmap = await createImageBitmap(this.file); // Creates a bitmap image from the uploaded file
|
||||
const shreadSize = 3; // Scale image factor for pixel art enhancement (must be odd)
|
||||
const bitmap = await createImageBitmap(this.file); // Create efficient bitmap from uploaded file
|
||||
const imageWidth = bitmap.width;
|
||||
const imageHeight = bitmap.height;
|
||||
|
||||
// ==================== PIXEL COUNTING SYSTEM ====================
|
||||
// Calculate total pixel count using standard width × height formula
|
||||
// This provides essential statistical information for the user interface
|
||||
const totalPixels = imageWidth * imageHeight;
|
||||
console.log(`Template pixel analysis - Dimensions: ${imageWidth}×${imageHeight} = ${totalPixels.toLocaleString()} pixels`);
|
||||
|
||||
// Store pixel count in instance property for access by template manager and UI components
|
||||
// This enables real-time statistics display and template comparison features
|
||||
this.pixelCount = totalPixels;
|
||||
|
||||
const templateTiles = {}; // Holds the template tiles
|
||||
|
||||
|
|
|
|||
213
src/main.js
213
src/main.js
|
|
@ -1,5 +1,19 @@
|
|||
/** The main file. Everything in the userscript is executed from here.
|
||||
* @since 0.0.0
|
||||
*
|
||||
* VERSION HISTORY:
|
||||
* 0.71.0 - Added minimize/maximize functionality and pixel counting system
|
||||
* Features added:
|
||||
* - Interactive minimize/maximize overlay with click-to-toggle functionality
|
||||
* - Fixed overlay dimensions: 60px width × 76px height in minimized state
|
||||
* - Smart element visibility control (hides all UI except icon and drag bar when minimized)
|
||||
* - Icon repositioning system (3px right offset) for better visual alignment in minimized state
|
||||
* - Comprehensive pixel counting system for template statistics
|
||||
* - Real-time pixel count display in template creation and rendering status messages
|
||||
* - Intelligent pixel counting for actively rendered templates with tile-based filtering
|
||||
* - Internationalized number formatting for large pixel counts (e.g., "1,234,567 pixels")
|
||||
* - Automatic state management with proper cleanup when switching between modes
|
||||
* - Enhanced user experience with visual feedback and status updates
|
||||
*/
|
||||
|
||||
import Overlay from './Overlay.js';
|
||||
|
|
@ -229,15 +243,210 @@ function observeBlack() {
|
|||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
/** Deploys the overlay to the page.
|
||||
/** Deploys the overlay to the page with minimize/maximize functionality.
|
||||
* Creates a responsive overlay UI that can toggle between full-featured and minimized states.
|
||||
*
|
||||
* Parent/child relationships in the DOM structure below are indicated by indentation.
|
||||
*
|
||||
* OVERLAY STATES:
|
||||
* - MAXIMIZED: Full UI with all controls, inputs, and status information visible
|
||||
* - MINIMIZED: Compact 60×76px interface showing only the Blue Marble icon and drag functionality
|
||||
*
|
||||
* FEATURES:
|
||||
* - Click-to-toggle functionality on the Blue Marble icon
|
||||
* - Automatic element visibility management
|
||||
* - Fixed dimensions for consistent minimized appearance
|
||||
* - Proper cleanup and restoration of all UI elements
|
||||
* - Visual feedback through alt-text updates
|
||||
* - Status message integration
|
||||
*
|
||||
* @since 0.58.3
|
||||
*/
|
||||
function buildOverlayMain() {
|
||||
let isMinimized = false; // Overlay state tracker (false = maximized, true = minimized)
|
||||
|
||||
overlay.addDiv({'id': 'bm-overlay', 'style': 'top: 10px; right: 75px;'})
|
||||
.addDiv({'id': 'bm-contain-header'})
|
||||
.addDiv({'id': 'bm-bar-drag'}).buildElement()
|
||||
.addImg({'alt': 'Blue Marble Icon', 'src': 'https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png'}).buildElement()
|
||||
.addImg({'alt': 'Blue Marble Icon - Click to minimize/maximize', 'src': 'https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png', 'style': 'cursor: pointer;'},
|
||||
(instance, img) => {
|
||||
/** Click event handler for overlay minimize/maximize functionality.
|
||||
*
|
||||
* Toggles between two distinct UI states:
|
||||
* 1. MINIMIZED STATE (60×76px):
|
||||
* - Shows only the Blue Marble icon and drag bar
|
||||
* - Hides all input fields, buttons, and status information
|
||||
* - Applies fixed dimensions for consistent appearance
|
||||
* - Repositions icon with 3px right offset for visual centering
|
||||
*
|
||||
* 2. MAXIMIZED STATE (responsive):
|
||||
* - Restores full functionality with all UI elements
|
||||
* - Removes fixed dimensions to allow responsive behavior
|
||||
* - Resets icon positioning to default alignment
|
||||
* - Shows success message when returning to maximized state
|
||||
*
|
||||
* IMPLEMENTATION DETAILS:
|
||||
* - Uses CSS display property manipulation for element visibility
|
||||
* - Maintains drag functionality in both states
|
||||
* - Updates accessibility text (alt attribute) based on current state
|
||||
* - Provides user feedback through status messages
|
||||
* - Ensures proper cleanup of all style overrides when switching states
|
||||
*
|
||||
* @param {Event} event - The click event object (implicit)
|
||||
*/
|
||||
img.addEventListener('click', () => {
|
||||
isMinimized = !isMinimized; // Toggle the current state
|
||||
|
||||
const overlay = document.querySelector('#bm-overlay');
|
||||
const header = document.querySelector('#bm-contain-header');
|
||||
const dragBar = document.querySelector('#bm-bar-drag');
|
||||
const coordsContainer = document.querySelector('#bm-contain-coords');
|
||||
const coordsButton = document.querySelector('#bm-button-coords');
|
||||
const enableButton = document.querySelector('#bm-button-enable');
|
||||
const coordInputs = document.querySelectorAll('#bm-contain-coords input');
|
||||
|
||||
// Pre-restore original dimensions when switching to maximized state
|
||||
// This ensures smooth transition and prevents layout issues
|
||||
if (!isMinimized) {
|
||||
overlay.style.width = "auto";
|
||||
overlay.style.maxWidth = "300px";
|
||||
overlay.style.minWidth = "200px";
|
||||
overlay.style.padding = "10px";
|
||||
}
|
||||
|
||||
// Define elements that should be hidden/shown during state transitions
|
||||
// Each element is documented with its purpose for maintainability
|
||||
const elementsToToggle = [
|
||||
'#bm-overlay h1', // Main title "Blue Marble"
|
||||
'#bm-contain-userinfo', // User information section (username, droplets, level)
|
||||
'#bm-overlay hr', // Visual separator lines
|
||||
'#bm-contain-automation > *:not(#bm-contain-coords)', // Automation section excluding coordinates
|
||||
'#bm-input-file-template', // Template file upload interface
|
||||
'#bm-contain-buttons-action', // Action buttons container
|
||||
`#${instance.outputStatusId}` // Status log textarea for user feedback
|
||||
];
|
||||
|
||||
// Apply visibility changes to all toggleable elements
|
||||
elementsToToggle.forEach(selector => {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
elements.forEach(element => {
|
||||
element.style.display = isMinimized ? 'none' : '';
|
||||
});
|
||||
});
|
||||
// Handle coordinate container and button visibility based on state
|
||||
if (isMinimized) {
|
||||
// ==================== MINIMIZED STATE CONFIGURATION ====================
|
||||
// In minimized state, we hide ALL interactive elements except the icon and drag bar
|
||||
// This creates a clean, unobtrusive interface that maintains only essential functionality
|
||||
|
||||
// Hide coordinate input container completely
|
||||
if (coordsContainer) {
|
||||
coordsContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide coordinate button (pin icon)
|
||||
if (coordsButton) {
|
||||
coordsButton.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide enable/disable template button
|
||||
if (enableButton) {
|
||||
enableButton.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide all coordinate input fields individually (failsafe)
|
||||
coordInputs.forEach(input => {
|
||||
input.style.display = 'none';
|
||||
});
|
||||
|
||||
// Apply fixed dimensions for consistent minimized appearance
|
||||
// These dimensions were chosen to accommodate the icon while remaining compact
|
||||
overlay.style.width = '60px'; // Fixed width for consistency
|
||||
overlay.style.height = '76px'; // Fixed height (60px + 16px for better proportions)
|
||||
overlay.style.maxWidth = '60px'; // Prevent expansion
|
||||
overlay.style.minWidth = '60px'; // Prevent shrinking
|
||||
overlay.style.padding = '8px'; // Comfortable padding around icon
|
||||
|
||||
// Apply icon positioning for better visual centering in minimized state
|
||||
// The 3px offset compensates for visual weight distribution
|
||||
img.style.marginLeft = '3px';
|
||||
|
||||
// Configure header layout for minimized state
|
||||
header.style.textAlign = 'center';
|
||||
header.style.margin = '0';
|
||||
header.style.marginBottom = '0';
|
||||
|
||||
// Ensure drag bar remains visible and properly spaced
|
||||
if (dragBar) {
|
||||
dragBar.style.display = '';
|
||||
dragBar.style.marginBottom = '0.25em';
|
||||
}
|
||||
} else {
|
||||
// ==================== MAXIMIZED STATE RESTORATION ====================
|
||||
// In maximized state, we restore all elements to their default functionality
|
||||
// This involves clearing all style overrides applied during minimization
|
||||
|
||||
// Restore coordinate container to default state
|
||||
if (coordsContainer) {
|
||||
coordsContainer.style.display = ''; // Show container
|
||||
coordsContainer.style.flexDirection = ''; // Reset flex layout
|
||||
coordsContainer.style.justifyContent = ''; // Reset alignment
|
||||
coordsContainer.style.alignItems = ''; // Reset alignment
|
||||
coordsContainer.style.gap = ''; // Reset spacing
|
||||
coordsContainer.style.textAlign = ''; // Reset text alignment
|
||||
coordsContainer.style.margin = ''; // Reset margins
|
||||
}
|
||||
|
||||
// Restore coordinate button visibility
|
||||
if (coordsButton) {
|
||||
coordsButton.style.display = '';
|
||||
}
|
||||
|
||||
// Restore enable button visibility and reset positioning
|
||||
if (enableButton) {
|
||||
enableButton.style.display = '';
|
||||
enableButton.style.marginTop = '';
|
||||
}
|
||||
|
||||
// Restore all coordinate input fields
|
||||
coordInputs.forEach(input => {
|
||||
input.style.display = '';
|
||||
});
|
||||
|
||||
// Reset icon positioning to default (remove minimized state offset)
|
||||
img.style.marginLeft = '';
|
||||
|
||||
// Restore overlay to responsive dimensions
|
||||
overlay.style.padding = '10px';
|
||||
|
||||
// Reset header styling to defaults
|
||||
header.style.textAlign = '';
|
||||
header.style.margin = '';
|
||||
header.style.marginBottom = '';
|
||||
|
||||
// Reset drag bar spacing
|
||||
if (dragBar) {
|
||||
dragBar.style.marginBottom = '0.5em';
|
||||
}
|
||||
|
||||
// Remove all fixed dimensions to allow responsive behavior
|
||||
// This ensures the overlay can adapt to content changes
|
||||
overlay.style.width = '';
|
||||
overlay.style.height = '';
|
||||
}
|
||||
|
||||
// ==================== ACCESSIBILITY AND USER FEEDBACK ====================
|
||||
// Update accessibility information for screen readers and tooltips
|
||||
|
||||
// Update alt text to reflect current state for screen readers and tooltips
|
||||
img.alt = isMinimized ?
|
||||
'Blue Marble Icon - Minimized (Click to maximize)' :
|
||||
'Blue Marble Icon - Maximized (Click to minimize)';
|
||||
|
||||
// No status message needed - state change is visually obvious to users
|
||||
});
|
||||
}
|
||||
).buildElement()
|
||||
.addHeader(1, {'textContent': name}).buildElement()
|
||||
.buildElement()
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,17 @@
|
|||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
z-index: 9000;
|
||||
transition: all 0.3s ease;
|
||||
max-width: 300px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Smooth transitions for minimize/maximize functionality */
|
||||
#bm-contain-userinfo,
|
||||
#bm-overlay hr,
|
||||
#bm-contain-automation,
|
||||
#bm-contain-buttons-action {
|
||||
transition: opacity 0.2s ease, height 0.2s ease;
|
||||
}
|
||||
|
||||
/* The entire overlay BUT it is cascading */
|
||||
|
|
@ -43,12 +54,41 @@ div#bm-overlay {
|
|||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* When minimized, adjust header container */
|
||||
#bm-contain-header[style*="text-align: center"] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Ensure overlay maintains consistent width when minimized */
|
||||
#bm-overlay[style*="padding: 5px"] {
|
||||
width: auto !important;
|
||||
max-width: 300px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
/* The Blue Marble image */
|
||||
#bm-overlay img {
|
||||
display: inline-block;
|
||||
height: 2.5em;
|
||||
margin-right: 1ch;
|
||||
vertical-align: middle;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
/* When overlay is minimized, adjust image styling */
|
||||
#bm-contain-header[style*="text-align: center"] img {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Ensure drag bar remains functional when minimized */
|
||||
#bm-bar-drag {
|
||||
transition: margin-bottom 0.2s ease;
|
||||
}
|
||||
|
||||
/* The Blue Marble header */
|
||||
|
|
|
|||
|
|
@ -1,8 +1,32 @@
|
|||
import Template from "./Template";
|
||||
import { numberToEncoded } from "./utils";
|
||||
|
||||
/** Manages the template system.
|
||||
* This class handles all external requests for modification to a Template.
|
||||
/** Manages the comprehensive template system with integrated pixel counting and statistics.
|
||||
*
|
||||
* This class handles all external requests for template modification, creation, and statistical analysis.
|
||||
* It serves as the central coordinator between template instances and the user interface, providing
|
||||
* real-time feedback on template statistics including pixel counts and rendering status.
|
||||
*
|
||||
* ENHANCED FEATURES:
|
||||
* - Real-time pixel counting and statistics display
|
||||
* - Intelligent template filtering based on active tiles
|
||||
* - Internationalized number formatting for large pixel counts
|
||||
* - Comprehensive status reporting with detailed template information
|
||||
* - Enhanced user feedback during template creation and rendering
|
||||
*
|
||||
* PIXEL COUNTING SYSTEM:
|
||||
* The template manager integrates with the Template class pixel counting system to provide:
|
||||
* - Individual template pixel counts during creation
|
||||
* - Aggregate pixel counts for multiple templates during rendering
|
||||
* - Smart filtering to count only actively displayed templates
|
||||
* - Formatted display of pixel statistics in user interface
|
||||
*
|
||||
* STATISTICAL INTEGRATION POINTS:
|
||||
* 1. Template Creation: Displays pixel count when new templates are processed
|
||||
* 2. Template Rendering: Shows aggregate pixel count for templates being displayed
|
||||
* 3. Tile Filtering: Counts pixels only for templates active in current viewport
|
||||
* 4. User Interface: Provides formatted statistics for status messages
|
||||
*
|
||||
* @since 0.55.8
|
||||
* @example
|
||||
* // JSON structure for a template
|
||||
|
|
@ -147,7 +171,11 @@ export default class TemplateManager {
|
|||
this.templatesArray = []; // Remove this to enable multiple templates (2/2)
|
||||
this.templatesArray.push(template); // Pushes the Template object instance to the Template Array
|
||||
|
||||
this.overlay.handleDisplayStatus(`Template created at ${coords.join(', ')}!`);
|
||||
// ==================== PIXEL COUNT DISPLAY SYSTEM ====================
|
||||
// Display pixel count statistics with internationalized number formatting
|
||||
// This provides immediate feedback to users about template complexity and size
|
||||
const pixelCountFormatted = new Intl.NumberFormat().format(template.pixelCount);
|
||||
this.overlay.handleDisplayStatus(`Template created at ${coords.join(', ')}! Total pixels: ${pixelCountFormatted}`);
|
||||
|
||||
console.log(Object.keys(this.templatesJSON.templates).length);
|
||||
console.log(this.templatesJSON);
|
||||
|
|
@ -177,18 +205,43 @@ export default class TemplateManager {
|
|||
|
||||
}
|
||||
|
||||
/** Draws all templates on that tile
|
||||
/** Draws all templates on the specified tile with intelligent pixel count reporting.
|
||||
*
|
||||
* This method handles the rendering of template overlays on individual tiles and provides
|
||||
* comprehensive statistics about the templates being displayed. It integrates with the
|
||||
* pixel counting system to give users real-time feedback about template complexity.
|
||||
*
|
||||
* PIXEL COUNTING INTEGRATION:
|
||||
* The method implements intelligent pixel counting that:
|
||||
* - Identifies templates that have content in the current tile
|
||||
* - Sums pixel counts only for templates actually being rendered
|
||||
* - Formats large numbers with locale-appropriate separators
|
||||
* - Provides detailed status messages with template and pixel statistics
|
||||
*
|
||||
* PERFORMANCE OPTIMIZATIONS:
|
||||
* - Filters templates by tile coordinates before processing
|
||||
* - Counts pixels only for active templates to avoid unnecessary calculations
|
||||
* - Uses efficient array operations for template filtering and aggregation
|
||||
* - Caches formatted numbers to avoid repeated formatting operations
|
||||
*
|
||||
* USER EXPERIENCE ENHANCEMENTS:
|
||||
* - Shows both template count and total pixel count in status messages
|
||||
* - Uses internationalized number formatting for better readability
|
||||
* - Provides immediate feedback when templates are being displayed
|
||||
* - Handles singular/plural forms correctly for template count
|
||||
*
|
||||
* @param {File} tileBlob - The pixels that are placed on a tile
|
||||
* @param {[number, number]} tileCoords - The tile coordinates [x, y]
|
||||
* @since 0.65.77
|
||||
*/
|
||||
async drawTemplateOnTile(tileBlob, tileCoords) {
|
||||
|
||||
const drawSize = this.tileSize * this.drawMult; // Draw multiplier
|
||||
const drawSize = this.tileSize * this.drawMult; // Calculate draw multiplier for scaling
|
||||
|
||||
// Format tile coordinates with proper padding for consistent lookup
|
||||
tileCoords = tileCoords[0].toString().padStart(4, '0') + ',' + tileCoords[1].toString().padStart(4, '0');
|
||||
|
||||
console.log(`Looking for "${tileCoords}"`);
|
||||
console.log(`Searching for templates in tile: "${tileCoords}"`);
|
||||
|
||||
const templateArray = this.templatesArray; // Stores a copy for sorting
|
||||
|
||||
|
|
@ -218,7 +271,31 @@ export default class TemplateManager {
|
|||
console.log(templateBlobs);
|
||||
|
||||
if (templateBlobs.length > 0) {
|
||||
this.overlay.handleDisplayStatus(`Displaying ${templateBlobs.length} template${templateBlobs.length == 1 ? '' : 's'}.`);
|
||||
// ==================== INTELLIGENT PIXEL COUNTING SYSTEM ====================
|
||||
// Calculate total pixel count for templates actively being displayed in this tile
|
||||
// This provides accurate statistics by counting only templates with content in the current viewport
|
||||
|
||||
const totalPixels = templateArray
|
||||
.filter(template => {
|
||||
// Filter templates to include only those with tiles matching current coordinates
|
||||
// This ensures we count pixels only for templates actually being rendered
|
||||
const matchingTiles = Object.keys(template.chunked).filter(tile =>
|
||||
tile.startsWith(tileCoords)
|
||||
);
|
||||
return matchingTiles.length > 0;
|
||||
})
|
||||
.reduce((sum, template) => sum + (template.pixelCount || 0), 0);
|
||||
|
||||
// Format pixel count with locale-appropriate thousands separators for better readability
|
||||
// Examples: "1,234,567" (US), "1.234.567" (DE), "1 234 567" (FR)
|
||||
const pixelCountFormatted = new Intl.NumberFormat().format(totalPixels);
|
||||
|
||||
// Display comprehensive status information including both template count and pixel statistics
|
||||
// This gives users immediate feedback about the complexity and scope of what's being rendered
|
||||
this.overlay.handleDisplayStatus(
|
||||
`Displaying ${templateBlobs.length} template${templateBlobs.length == 1 ? '' : 's'}. ` +
|
||||
`Total pixels: ${pixelCountFormatted}`
|
||||
);
|
||||
}
|
||||
|
||||
const tileBitmap = await createImageBitmap(tileBlob);
|
||||
|
|
|
|||
Loading…
Reference in a new issue