A Deep Dive into Map Maker Software's Latest Codebase Updates

Andrew Lukes
6 min readNov 22, 2023

--

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.

Left: BuckeFill Cursor Center: Prefill Right: Postfill

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.

slider for changing the endpoint

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);
};

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!

Photo by Jan Antonin Kolar on Unsplash

--

--

Andrew Lukes

Introducing Andrew Lukes: a Prague web dev & language enthusiast who shares his ideas on Medium. You can visit andrewebdev.online to see some of my projects