I've been struggling with a particular issue for some time now.
Currently, I'm developing a web application using TypeScript, React, and Google Maps. For the markers on the map, I aim to use custom images generated at runtime based on various parameters. These images consist of a circle and a triangle that indicates a direction at a specific angle with different colors. Examples of what the images should look like can be seen here: Image 1 and Image 2.
The number of these images can vary from 1 to 300 depending on user preferences. Additionally, the top of the triangle should start at the map coordinates. When multiple markers are in close proximity, they should appear similar to this image: Image 3.
I have managed to create and place the images on the map as intended. However, the problem arises when the images are too large and overlap when near each other. This results in the markers not being clickable until zoomed in, creating a situation like the one depicted here: Image 4.
My objective is to crop out the transparent areas so only the circle and triangle remain usable for the map. I have attempted two methods for this - one involving the canvas element and the other utilizing SVG elements. Both processes involve drawing the circle first, then the triangle, followed by rotation.
When working with SVGs, I was able to identify the bounding rectangle using getBBox()
or getBoundingClientRect()
. However, an issue arose when the images were not loaded into the DOM, resulting in no output from these methods until the SVG was added to the DOM. This approach proved inefficient as I would have to add every image to the DOM before processing it, adding it to the map, and finally removing it from the DOM.
With the canvas method, I found a function online that scans every pixel on the canvas, returning the objects within it. While effective, this process became sluggish with numerous elements present. Another failed attempt involved locating the rotated coordinates using a formula:
x1 = x * Math.cos(angle * Math.PI / 180) - y * Math.sin(angle * Math.PI / 180)
y1 = x * Math.sin(angle * Math.PI / 180) + y * Math.cos(angle * Math.PI / 180)
So, my question remains - what is the best approach to solving this dilemma?
Thank you for your assistance.
Here's the code snippet outlining the canvas and SVG drawing functions:
// Code for canvas icon creation
const drawMarkerIconCanvas = (
angle?: number | null,
arrowFillColor?: string,
circleFillColor?: string,
strokeColor?: string,
scale?: number,
text?: string,
textColor?: string) => {
// Function implementation goes here...
}
// Code for SVG icon creation
const drawMarkerIconSVG = (angle?: number | null,
arrowFillColor?: string,
circleFillColor?: string,
strokeColor?: string,
scale?: number,
text?: string,
textColor?: string) => {
// Function implementation goes here...
}