Skip to content

Commit 440467d

Browse files
committed
new bookmarklet: siteSpecific_GoogleMaps_CustomMearsureDistance.js
1 parent 442c2c8 commit 440467d

File tree

3 files changed

+244
-3
lines changed

3 files changed

+244
-3
lines changed
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
javascript:(function(){
2+
/* Style values */
3+
const googleMapsCustomMeasureDistanceStyle = `
4+
/*all * { cursor: crosshair; } */
5+
6+
button#custom-measure-btn {
7+
position: fixed;
8+
bottom: 150px;
9+
right: 20px;
10+
z-index: 20000;
11+
padding: 12px;
12+
background: #4285f4;
13+
color: white;
14+
border: none;
15+
border-radius: 8px;
16+
cursor: pointer;
17+
font-weight: bold;
18+
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
19+
}
20+
`;
21+
22+
/************************************* SUPPORT FUNCTIONS *************************************/
23+
/* Add draw events to map canvas */
24+
const googleMapsCustomMeasureDistanceDraw = () => {
25+
/* global variables for inserted script */
26+
const googleMapsCustomMeasureDistanceLabelEl = /* select current scale */
27+
document.getElementById('U5ELMd');
28+
const googleMapsCustomMeasureDistanceBarEl = /* get scal in pixels */
29+
document.querySelector('.Ty7QWe');
30+
31+
/* notify update not found */
32+
if (!googleMapsCustomMeasureDistanceLabelEl || !googleMapsCustomMeasureDistanceBarEl)
33+
return alert('Scale bar not found!');
34+
35+
let getRatio = () => /* get the ration of pixels to scale */
36+
parseInt(googleMapsCustomMeasureDistanceLabelEl.innerText.match(/\d+/)[0]) / parseInt(googleMapsCustomMeasureDistanceBarEl.style.width);
37+
38+
let getUnit = () => /* get the digit value of scale */
39+
googleMapsCustomMeasureDistanceLabelEl.innerText.replace(/[0-9]|\s/g, '');
40+
41+
if (document.getElementById('custom-measure-btn')) return; /* no duplicates */
42+
43+
let btn = /* button to start */
44+
document.createElement('button');
45+
46+
/* prepare button */
47+
btn.id = 'custom-measure-btn'; /* unique identifier */
48+
btn.innerText = '📏 Custom Measure'; /* data */
49+
document.body.appendChild(btn); /* add to page */
50+
51+
/* prepare svg */
52+
let svg = /* create svg */
53+
document.createElementNS('http://www.w3.org/2000/svg', 'svg');
54+
svg.style.cssText = /* style inline*/
55+
'position:fixed; top:0; left:0; width:100%; height:100%; z-index:19999; pointer-events:none; display:none;';
56+
document.body.appendChild(svg); /* add to page */
57+
58+
/* set switches */
59+
let isDrawingMode = false, activeNode = null, startPt = null;
60+
61+
/* add click event to button */
62+
btn.onclick = (e) => {
63+
e.stopPropagation(); /* toggle */
64+
65+
/* select inserted style tag */
66+
let s = document.getElementById("googleMapsCustomMeasureDistanceStyle");
67+
68+
/* update global cursor style */
69+
s.innerText = /* determine status */
70+
isDrawingMode ?
71+
s.innerText.replace("/*all*/ * { cursor: crosshair; }", "/*all * { cursor: crosshair; } */"): /* comment out */
72+
s.innerText.replace("/*all * { cursor: crosshair; } */", "/*all*/ * { cursor: crosshair; }"); /* uncomment */
73+
74+
isDrawingMode = /* determine status */
75+
!isDrawingMode;
76+
77+
/* config button per status */
78+
btn.style.background = /* toggle draw mode */
79+
isDrawingMode ? '#db4437' : '#4285f4';
80+
81+
btn.innerText = /* button text */
82+
isDrawingMode ? '🛑 Stop' : '📏 Draggable Measure';
83+
84+
svg.style.display = /* show or hide svg */
85+
isDrawingMode ? 'block' : 'none';
86+
87+
svg.style.pointerEvents = /* toggle pointer events */
88+
isDrawingMode ? 'all' : 'none';
89+
};
90+
91+
/* line functionality */
92+
var updateLine = (group) => {
93+
/* draw line and annotations */
94+
let p1 = group.childNodes[0]; /* start vector */
95+
let p2 = group.childNodes[1]; /* end vector */
96+
let line = group.childNodes[2]; /* line & dimen. */
97+
let txt = group.childNodes[3]; /* measurement */
98+
99+
/* listen for current mouse position */
100+
let x1 = +p1.getAttribute('cx'); /* current x position */
101+
let y1 = +p1.getAttribute('cy'); /* current y position */
102+
let x2 = +p2.getAttribute('cx'); /* end x position */
103+
let y2 = +p2.getAttribute('cy'); /* end y position */
104+
105+
/* draw the custom line */
106+
line.setAttribute('x1', x1);
107+
line.setAttribute('y1', y1);
108+
line.setAttribute('x2', x2);
109+
line.setAttribute('y2', y2);
110+
111+
/* get value of current scale */
112+
let dist = (Math.sqrt((x2-x1)**2 + (y2-y1)**2) * getRatio()).toFixed(2);
113+
114+
/* add annotations */
115+
txt.setAttribute('x', (x1+x2)/2 + 10);
116+
txt.setAttribute('y', (y1+y2)/2);
117+
txt.textContent = dist + ' ' + getUnit();
118+
};
119+
120+
/* update position for lines */
121+
svg.onmousedown = (e) => {
122+
if (e.target.tagName === 'circle') {
123+
activeNode = e.target;
124+
} else if (isDrawingMode) {
125+
if (!startPt) {
126+
startPt = { /* set starting point */
127+
x: e.clientX,
128+
y: e.clientY
129+
};
130+
} else {
131+
let g = /* add svg g element */
132+
document.createElementNS('http://www.w3.org/2000/svg', 'g');
133+
134+
/* start and end vectors */
135+
let c1 = /* add start vector circle indicator */
136+
createCircle(startPt.x, startPt.y);
137+
let c2 = /* add end vector circle indicator */
138+
createCircle(e.clientX, e.clientY);
139+
140+
/* draw line betwwen vectors */
141+
let l = /* add svg line element */
142+
document.createElementNS('http://www.w3.org/2000/svg', 'line');
143+
144+
/* prepare line */
145+
l.setAttribute('stroke', '#4285f4');
146+
l.setAttribute('stroke-width', '4');
147+
148+
/* distance of line */
149+
let t = /* add svg text element */
150+
document.createElementNS('http://www.w3.org/2000/svg', 'text');
151+
/* inline style text */
152+
t.style.cssText = 'font:bold 16px sans-serif; paint-order:stroke; stroke:white; stroke-width:4px; pointer-events:none;';
153+
154+
/* create vector representative circles */
155+
g.append(c1, c2, l, t);
156+
svg.appendChild(g);
157+
158+
/* add circles at end of line*/
159+
updateLine(g);
160+
161+
/* toggle switch */
162+
startPt = null;
163+
}
164+
}
165+
};
166+
167+
svg.onmousemove = (e) => {
168+
/* check if moving vector circle */
169+
if (activeNode) {
170+
activeNode.setAttribute('cx', e.clientX);
171+
activeNode.setAttribute('cy', e.clientY);
172+
updateLine(activeNode.parentNode);
173+
}
174+
};
175+
176+
/* toggle switch */
177+
window.onmouseup = () => activeNode = null;
178+
179+
180+
var createCircle = (x, y) => {
181+
let c = /* create the vector representative circle */
182+
document.createElementNS('http://www.w3.org/2000/svg', 'circle');
183+
184+
/* prepare circle */
185+
c.setAttribute('cx', x);
186+
c.setAttribute('cy', y);
187+
c.setAttribute('r', 8);
188+
c.setAttribute('fill', '#db4437');
189+
c.style.cursor = 'move';
190+
return c;
191+
};
192+
};
193+
194+
function googleMapsCustomMearsureDistance() {
195+
let style = document.createElement("style");
196+
let script = document.createElement('script');
197+
198+
/* no duplicates */
199+
if (document.getElementById("googleMapsCustomMeasureDistanceStyle")) return;
200+
201+
/* else */
202+
/* prepare style and script */
203+
style.setAttribute("id", "googleMapsCustomMeasureDistanceStyle");
204+
style.innerText = /* use global variable */
205+
googleMapsCustomMeasureDistanceStyle;
206+
207+
script.textContent = /* make self calling function */
208+
'(' + googleMapsCustomMeasureDistanceDraw + ')();';
209+
210+
/* add style and script to page */
211+
document.documentElement.prepend(style);
212+
document.documentElement.appendChild(script);
213+
214+
/* no need for script after it calls itself */
215+
script.remove();
216+
}
217+
googleMapsCustomMearsureDistance();
218+
})();

0 commit comments

Comments
 (0)