Skip to content

Commit fd70889

Browse files
committed
Add consolidated demo: all_demos.html
1 parent ce14c7e commit fd70889

File tree

1 file changed

+226
-0
lines changed

1 file changed

+226
-0
lines changed

devtools/demos/all_demos.html

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Custom Marker Functions - All Demos</title>
6+
<script src="../../dist/plotly.js"></script>
7+
<style>
8+
body { font-family: Arial, sans-serif; margin: 20px; max-width: 900px; margin: 0 auto; padding: 20px; }
9+
h1 { border-bottom: 2px solid #3b82f6; padding-bottom: 10px; }
10+
h2 { color: #333; margin-top: 40px; }
11+
.plot { width: 100%; height: 400px; margin: 20px 0; }
12+
.info { background: #e7f3ff; padding: 10px; border-left: 4px solid #3b82f6; margin: 10px 0; }
13+
pre { background: #f5f5f5; padding: 15px; overflow-x: auto; font-size: 13px; }
14+
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; }
15+
</style>
16+
</head>
17+
<body>
18+
<h1>Custom Marker Functions</h1>
19+
<div class="info">
20+
Pass functions as <code>marker.symbol</code> to create custom shapes.<br>
21+
<strong>Simple:</strong> <code>function(r)</code> — r is marker radius<br>
22+
<strong>Data-aware:</strong> <code>function(r, customdata)</code> — access per-point data
23+
</div>
24+
25+
<!-- Demo 1: Basic custom markers -->
26+
<h2>1. Basic Custom Markers</h2>
27+
<p>Define functions returning SVG path strings. Mix with built-in symbols.</p>
28+
<div id="plot1" class="plot"></div>
29+
<pre>
30+
// Heart shape
31+
function heart(r) {
32+
var x = r * 0.6, y = r * 0.8;
33+
return 'M0,' + (-y/2) +
34+
'C' + (-x) + ',' + (-y) + ' ' + (-x*2) + ',' + (-y/3) + ' ' + (-x*2) + ',0' +
35+
'C' + (-x*2) + ',' + (y/2) + ' 0,' + y + ' 0,' + (y*1.5) +
36+
'C0,' + y + ' ' + (x*2) + ',' + (y/2) + ' ' + (x*2) + ',0' +
37+
'C' + (x*2) + ',' + (-y/3) + ' ' + x + ',' + (-y) + ' 0,' + (-y/2) + 'Z';
38+
}
39+
40+
// 5-point star
41+
function star(r) {
42+
var path = 'M';
43+
for (var i = 0; i < 10; i++) {
44+
var rad = i % 2 === 0 ? r : r * 0.4;
45+
var ang = i * Math.PI / 5 - Math.PI / 2;
46+
path += (i ? 'L' : '') + (rad * Math.cos(ang)).toFixed(2) + ',' + (rad * Math.sin(ang)).toFixed(2);
47+
}
48+
return path + 'Z';
49+
}
50+
51+
Plotly.newPlot('plot1', [{
52+
x: [1, 2, 3, 4, 5],
53+
y: [2, 3, 4, 3, 2],
54+
mode: 'markers+lines',
55+
marker: {
56+
symbol: [heart, star, 'circle', star, heart], // mix functions and strings
57+
size: 25,
58+
color: ['red', 'gold', 'blue', 'gold', 'red']
59+
}
60+
}]);</pre>
61+
62+
<!-- Demo 2: Data-aware markers -->
63+
<h2>2. Data-Aware Markers</h2>
64+
<p>Access <code>customdata[i]</code> to vary shape per point.</p>
65+
<div id="plot2" class="plot"></div>
66+
<pre>
67+
function shapeByData(r, customdata) {
68+
if (customdata === 'star') {
69+
// Star shape
70+
var path = 'M';
71+
for (var i = 0; i < 10; i++) {
72+
var rad = i % 2 === 0 ? r : r * 0.4;
73+
var ang = i * Math.PI / 5 - Math.PI / 2;
74+
path += (i ? 'L' : '') + (rad * Math.cos(ang)).toFixed(2) + ',' + (rad * Math.sin(ang)).toFixed(2);
75+
}
76+
return path + 'Z';
77+
}
78+
if (customdata === 'big') {
79+
r *= 1.4; // Larger diamond
80+
}
81+
// Default: diamond
82+
return 'M' + r + ',0L0,' + r + 'L-' + r + ',0L0,-' + r + 'Z';
83+
}
84+
85+
Plotly.newPlot('plot2', [{
86+
x: [1, 2, 3, 4],
87+
y: [1, 1, 1, 1],
88+
customdata: ['normal', 'big', 'star', 'normal'],
89+
mode: 'markers',
90+
marker: { symbol: shapeByData, size: 25, color: '#10b981' }
91+
}]);</pre>
92+
93+
<!-- Demo 3: Weather map -->
94+
<h2>3. Weather Map</h2>
95+
<p>Complex example: sun, cloud, and wind barbs based on weather data.</p>
96+
<div id="plot3" class="plot"></div>
97+
<pre>
98+
function weatherMarker(r, data) {
99+
if (data.type === 'sunny') {
100+
// Sun: circle with rays
101+
var cr = r * 0.5, path = 'M' + cr + ',0A' + cr + ',' + cr + ' 0 1,1 -' + cr + ',0A' + cr + ',' + cr + ' 0 1,1 ' + cr + ',0';
102+
for (var i = 0; i < 8; i++) {
103+
var ang = i * Math.PI / 4;
104+
path += 'M' + ((cr+2) * Math.cos(ang)).toFixed(1) + ',' + ((cr+2) * Math.sin(ang)).toFixed(1) +
105+
'L' + ((cr+r*0.4) * Math.cos(ang)).toFixed(1) + ',' + ((cr+r*0.4) * Math.sin(ang)).toFixed(1);
106+
}
107+
return path;
108+
}
109+
if (data.type === 'cloudy') {
110+
return 'M-8,3 A6,6 0 1,1 -2,-4 A7,7 0 1,1 8,-2 A5,5 0 1,1 10,3 Z';
111+
}
112+
if (data.type === 'wind') {
113+
// Wind barb: staff + barbs based on speed
114+
var path = 'M0,' + r + 'L0,-' + r, y = -r;
115+
for (var i = 0; i < Math.min(data.speed, 3); i++) {
116+
path += 'M0,' + y + 'L' + (r*0.6) + ',' + (y + r*0.3);
117+
y += r * 0.3;
118+
}
119+
return path;
120+
}
121+
return 'M' + r + ',0A' + r + ',' + r + ' 0 1,0 -' + r + ',0A' + r + ',' + r + ' 0 1,0 ' + r + ',0';
122+
}
123+
124+
var locations = [
125+
{ name: 'Seattle', lon: -122, lat: 47, weather: { type: 'cloudy' } },
126+
{ name: 'SF', lon: -122, lat: 38, weather: { type: 'sunny' } },
127+
{ name: 'Denver', lon: -105, lat: 40, weather: { type: 'sunny' } },
128+
{ name: 'Chicago', lon: -88, lat: 42, weather: { type: 'cloudy' } },
129+
{ name: 'NYC', lon: -74, lat: 41, weather: { type: 'cloudy' } },
130+
{ name: 'Miami', lon: -80, lat: 26, weather: { type: 'sunny' } },
131+
// Wind arrows (jet stream)
132+
{ lon: -115, lat: 46, weather: { type: 'wind', direction: 100, speed: 3 } },
133+
{ lon: -100, lat: 42, weather: { type: 'wind', direction: 120, speed: 2 } },
134+
{ lon: -85, lat: 36, weather: { type: 'wind', direction: 150, speed: 1 } }
135+
];
136+
137+
Plotly.newPlot('plot3', [{
138+
x: locations.map(l => l.lon),
139+
y: locations.map(l => l.lat),
140+
customdata: locations.map(l => l.weather),
141+
text: locations.map(l => l.name || ''),
142+
mode: 'markers+text',
143+
textposition: 'bottom center',
144+
marker: {
145+
symbol: weatherMarker,
146+
size: 30,
147+
color: locations.map(l => ({ sunny: '#FFD700', cloudy: '#708090', wind: '#4169E1' }[l.weather.type])),
148+
angle: locations.map(l => l.weather.direction || 0)
149+
}
150+
}], { xaxis: { range: [-130, -70] }, yaxis: { range: [20, 52], scaleanchor: 'x' } });</pre>
151+
152+
<script>
153+
// === Demo 1: Basic markers ===
154+
function heart(r) {
155+
var x = r * 0.6, y = r * 0.8;
156+
return 'M0,' + (-y/2) + 'C' + (-x) + ',' + (-y) + ' ' + (-x*2) + ',' + (-y/3) + ' ' + (-x*2) + ',0C' + (-x*2) + ',' + (y/2) + ' 0,' + y + ' 0,' + (y*1.5) + 'C0,' + y + ' ' + (x*2) + ',' + (y/2) + ' ' + (x*2) + ',0C' + (x*2) + ',' + (-y/3) + ' ' + x + ',' + (-y) + ' 0,' + (-y/2) + 'Z';
157+
}
158+
function star(r) {
159+
var path = 'M';
160+
for (var i = 0; i < 10; i++) {
161+
var rad = i % 2 === 0 ? r : r * 0.4, ang = i * Math.PI / 5 - Math.PI / 2;
162+
path += (i ? 'L' : '') + (rad * Math.cos(ang)).toFixed(2) + ',' + (rad * Math.sin(ang)).toFixed(2);
163+
}
164+
return path + 'Z';
165+
}
166+
Plotly.newPlot('plot1', [{
167+
x: [1, 2, 3, 4, 5], y: [2, 3, 4, 3, 2], mode: 'markers+lines',
168+
marker: { symbol: [heart, star, 'circle', star, heart], size: 25, color: ['red', 'gold', 'blue', 'gold', 'red'] }
169+
}], { title: 'Mix custom functions with built-in symbols' });
170+
171+
// === Demo 2: Data-aware ===
172+
function shapeByData(r, customdata) {
173+
if (customdata === 'star') {
174+
var path = 'M';
175+
for (var i = 0; i < 10; i++) {
176+
var rad = i % 2 === 0 ? r : r * 0.4, ang = i * Math.PI / 5 - Math.PI / 2;
177+
path += (i ? 'L' : '') + (rad * Math.cos(ang)).toFixed(2) + ',' + (rad * Math.sin(ang)).toFixed(2);
178+
}
179+
return path + 'Z';
180+
}
181+
if (customdata === 'big') r *= 1.4;
182+
return 'M' + r + ',0L0,' + r + 'L-' + r + ',0L0,-' + r + 'Z';
183+
}
184+
Plotly.newPlot('plot2', [{
185+
x: [1, 2, 3, 4], y: [1, 1, 1, 1], customdata: ['normal', 'big', 'star', 'normal'],
186+
mode: 'markers', marker: { symbol: shapeByData, size: 25, color: '#10b981' }
187+
}], { title: 'Shape varies by customdata value', xaxis: { range: [0, 5] } });
188+
189+
// === Demo 3: Weather map ===
190+
function weatherMarker(r, data) {
191+
if (data.type === 'sunny') {
192+
var cr = r * 0.5, path = 'M' + cr + ',0A' + cr + ',' + cr + ' 0 1,1 -' + cr + ',0A' + cr + ',' + cr + ' 0 1,1 ' + cr + ',0';
193+
for (var i = 0; i < 8; i++) {
194+
var ang = i * Math.PI / 4;
195+
path += 'M' + ((cr+2) * Math.cos(ang)).toFixed(1) + ',' + ((cr+2) * Math.sin(ang)).toFixed(1) + 'L' + ((cr+r*0.4) * Math.cos(ang)).toFixed(1) + ',' + ((cr+r*0.4) * Math.sin(ang)).toFixed(1);
196+
}
197+
return path;
198+
}
199+
if (data.type === 'cloudy') return 'M-8,3 A6,6 0 1,1 -2,-4 A7,7 0 1,1 8,-2 A5,5 0 1,1 10,3 Z';
200+
if (data.type === 'wind') {
201+
var path = 'M0,' + r + 'L0,-' + r, y = -r;
202+
for (var i = 0; i < Math.min(data.speed, 3); i++) { path += 'M0,' + y + 'L' + (r*0.6) + ',' + (y + r*0.3); y += r * 0.3; }
203+
return path;
204+
}
205+
return 'M' + r + ',0A' + r + ',' + r + ' 0 1,0 -' + r + ',0A' + r + ',' + r + ' 0 1,0 ' + r + ',0';
206+
}
207+
var locations = [
208+
{ name: 'Seattle', lon: -122, lat: 47, weather: { type: 'cloudy' } },
209+
{ name: 'SF', lon: -122, lat: 38, weather: { type: 'sunny' } },
210+
{ name: 'Denver', lon: -105, lat: 40, weather: { type: 'sunny' } },
211+
{ name: 'Chicago', lon: -88, lat: 42, weather: { type: 'cloudy' } },
212+
{ name: 'NYC', lon: -74, lat: 41, weather: { type: 'cloudy' } },
213+
{ name: 'Miami', lon: -80, lat: 26, weather: { type: 'sunny' } },
214+
{ lon: -115, lat: 46, weather: { type: 'wind', direction: 100, speed: 3 } },
215+
{ lon: -100, lat: 42, weather: { type: 'wind', direction: 120, speed: 2 } },
216+
{ lon: -85, lat: 36, weather: { type: 'wind', direction: 150, speed: 1 } }
217+
];
218+
Plotly.newPlot('plot3', [{
219+
x: locations.map(l => l.lon), y: locations.map(l => l.lat),
220+
customdata: locations.map(l => l.weather), text: locations.map(l => l.name || ''),
221+
mode: 'markers+text', textposition: 'bottom center',
222+
marker: { symbol: weatherMarker, size: 30, color: locations.map(l => ({ sunny: '#FFD700', cloudy: '#708090', wind: '#4169E1' }[l.weather.type])), angle: locations.map(l => l.weather.direction || 0) }
223+
}], { title: 'Weather icons with wind direction via marker.angle', xaxis: { range: [-130, -70] }, yaxis: { range: [20, 52], scaleanchor: 'x' } });
224+
</script>
225+
</body>
226+
</html>

0 commit comments

Comments
 (0)