A Deep Dive into Map Maker Software's Latest Codebase Updates
Check out the newest code improvements and web development tips
Welcome to the behind-the-scenes journey of Map Maker Online’s (MMO) evolving codebase! In this article, we’ll uncover the latest updates that not only refine the map-making experience but also empower you to shape the future of M.M.O’s development.
· Code Unveiled: A Peek into M.M.O’s Latest Features
∘ Expanded Projects Context
∘ Drawing Layer Expansion
∘ Enhanced Frontline Editor
∘ Organized Settings
∘ Debugging Compiler
· Section 2: Lessons Learned and Tips Shared
∘ Make Sure To Use IDs Not Indexes
∘ Learn Typescript ASAP
· Useful Utility React Functions
· Section 3: Join the Coding Adventure
· Conclusion:
Section 1: A Peek into M.M.O’s Latest Features
Expanded Projects Context
The Global Data Object: This object is supposed to provide easy access to useful values. Previously, I was only storing the mouseDownTime here. Now I have also begun keeping track of the mouse position as well as the mouse position relative to the canvas editor.
const [globalData, setGlobalData] = useState<GlobalDataType>({
mouseDownTime: 0,
mousePosition: null,
editorRelativePosition: null,
});
For now, I mostly use this information for debugging purposes, but I am sure, it will become more useful later.
Reorganized Signals: In order to decrease the complexity of my objects, I have divided the settings signal into frontline settings, marker settings, etc. Thanks to it I can access variables using shorter names for example:
export const settings: Settings = signal({
markerSettings: {
//
}
frontLineSettings {
//
activeFrontline: null,
//
}
});
const x = settings.value.frontlineSettings.activeFrontline
export const settings: Settings = signal({
//
});
export const markerSettings: Signal<MarkerSettings> = signal({
//
})
export const frontLineSettings: FrontLineSettings = signal({
//
activeFrontline: null,
//
});
const x = frontLineSettings.value.activeFrontline
On top of that, I have put the drawing layer state into the Signals folder for global access, since I need to reach it from settings as well as from the drawing layer.
Drawing Layer Expansion
Bucket Fill Feature: You can now fill an area using the new bucket fill feature. I have still some problems with filling spaces around the edges of circles. For edged surfaces, it works perfectly. You even get a bucket-fill cursor.
Clear Canvas Button: Clear the whole drawing canvas with a single click! If time allows, I will add this button to all of the layers
Enhanced Frontline Editor
I have worked on improving the user experience in this layer.
Instead of setting the end of the line by clicking on a point, you can set it inside the settings using a slider.
This circumvents the problem, that when deleting a point the end of the frontline changed due to input conflict
New Frontline-Adding Function: This function allows me to easily append new frontlines into the frontline settings
const onMountFrontLineData: FrontlineData = {
idNum: uuidv4(),
points: [],
endPoint : null,
thickness: 4,
color: frontLineSettings.value.frontLineColor,
};
const addFrontline = () => {
// Create a new instance of onMountFrontLineData with a unique ID
const newFrontLineData = {
...onMountFrontLineData,
idNum: uuidv4(),
};
// Add the new frontline to the frontLines array
frontLineSettings.value.frontLines.push(newFrontLineData);
// Set the new frontline as active
frontLineSettings.value.activeFrontline = newFrontLineData;
};
Organized Settings
Columns Component: Utilizing MUI design I have created a custom column component, which I use throughout all the settings to unify the design.
It is true that it still needs some reworking, but thanks to the change I can change it all in one place
type SettingsColumnProps = {
children: React.ReactNode;
sx?: React.CSSProperties; // Allow additional styles to be passed through props
styles?: React.CSSProperties; // Fix the type here
};
const SettingsColumn: React.FC<SettingsColumnProps> = ({ children, sx, styles }) => {
const theme = useTheme();
return (
<Paper sx={{
maxWidth: styles?.maxWidth || '200px', // Adjusted the property name to camelCase
minWidth: '150px',
backgroundColor: theme.palette.primary.dark,
padding: theme.spacing(2),
overflowY: 'auto',
height: '250px',
margin: '2px',
...sx, // Spread additional styles passed through props
}}>
{children}
</Paper>
);
};
export default SettingsColumn;
*Code for settings column component
Dividing Code into subfolders: All of the code for settings columns became way too long, so each column has its own component (wrapped inside a SettingsCollumn grid for design unification). This ensures further readability.
Debugging Compiler
I have rewritten the function, for printing markers on canvas. Thanks to it, you can see them in the compiled version even with their background image.
Section 2: Lessons Learned and Tips Shared
These are the latest tips from me after the latest coding sessions.
Make Sure To Use IDs Not Indexes
I have started using IDs in the frontline layer after finding a bug with deleting the points in the frontlines. All of the points would move one space back and take the information of the previous marker. This was caused by using indexes of the points instead of IDs.
Although it is easier, you should absolutely not use indexes, since it causes weird behavior. Especially when you change the array from which you have taken the index. I recommend the UUID library, which assigns a custom string every time you ask for a unique ID, here is how to use it
npm i uuidv4
///
import { uuid } from "uuidv4";
///
x = uuid()
Learn Typescript ASAP
If you are already familiar with your vanilla JavaScript or React environments, the next step should be to learn Typescript. I can't overstate, how useful it already proved to me. When I go back to writing javascript without type checks in a different project, the code feels very fragile and breaks easily.
Useful Utility React Functions
canvas offset function: It will give you the position of the canvas relative to the top edge of the window
export const topLeftPosition: Signal<Vector2> = signal({x:0,y:0})
const YourCanvas = () => {
const updateEditorTopLeftPosition = () => {
console.log("setting topleft", canvasRef.current !== null);
if (canvasRef.current) {
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
const newTopLeftPosition: Vector2 = { x: rect.left, y: rect.top };
topLeftPosition.value = newTopLeftPosition;
}
};
useEffect(() => {
// Attach event listener on component mount
window.addEventListener("resize", updateEditorTopLeftPosition);
updateEditorTopLeftPosition();
// Detach event listener on component unmount
return () => {
window.removeEventListener("resize", updateEditorTopLeftPosition);
};
}, []);
return <>Your Canvas</>
}
move by offset function: You can add a position and a distance in two directions to move it and it will return a new position
export const movePosByOffset = (position: Vector2, offset: number | Vector2): Vector2 => {
if (typeof offset === 'number') {
// If offset is a number, apply it to both x and y values
return { x: position.x + offset, y: position.y + offset };
} else {
// If offset is a Vector2, apply its x and y values separately
return { x: position.x + offset.x, y: position.y + offset.y };
}
};
// example usage
const handleMouseMove = (e: MouseEvent) => {
const newTopLeftPosition = {x: e.clientX, y: e.clientY}
const newPosition = movePosByOffset(newTopLeftPosition, -radius/2)
// console.log(newPosition, mousePosition)
onDrag?.(newPosition);
};
Section 3: Join the Coding Adventure
Join Our Discord Server For the Latest Updates
Conclusion:
As we navigate through the latest updates, absorb valuable lessons, and extend an invitation to join our coding adventure, we’re not just talking about code. We’re building a community around creativity and innovation. Let’s embark on this exciting journey together!