Last active
July 28, 2025 06:45
-
-
Save jsundram/4f2ccff5bfe8438f0cface4a7568ecea to your computer and use it in GitHub Desktop.
flowers with geometric petals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Pentagon Flower Generator</title> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
min-height: 100vh; | |
box-sizing: border-box; | |
} | |
.container { | |
background: white; | |
border-radius: 15px; | |
padding: 30px; | |
box-shadow: 0 10px 30px rgba(0,0,0,0.2); | |
width: 100%; | |
box-sizing: border-box; | |
} | |
h1 { | |
text-align: center; | |
color: #333; | |
margin-bottom: 30px; | |
font-size: clamp(1.5rem, 4vw, 2.5rem); | |
} | |
.preview-section { | |
text-align: center; | |
margin-bottom: 30px; | |
} | |
.controls { | |
display: flex; | |
justify-content: center; | |
gap: 15px; | |
margin: 20px 0; | |
flex-wrap: wrap; | |
align-items: flex-start; | |
} | |
.control-group { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 8px; | |
min-width: 120px; | |
} | |
label { | |
font-weight: bold; | |
color: #555; | |
font-size: 0.9rem; | |
text-align: center; | |
} | |
input[type="range"] { | |
width: 100px; | |
min-width: 80px; | |
} | |
input[type="number"] { | |
width: 70px; | |
padding: 5px; | |
border: 2px solid #ddd; | |
border-radius: 5px; | |
text-align: center; | |
font-size: 0.9rem; | |
} | |
#svgContainer { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
margin: 20px 0; | |
} | |
#svgContainer svg { | |
max-width: 100%; | |
height: auto; | |
border: 2px solid #333; | |
border-radius: 10px; | |
background: white; | |
box-shadow: 0 5px 15px rgba(0,0,0,0.1); | |
} | |
.code-section { | |
margin-top: 30px; | |
} | |
.code-section h2 { | |
color: #333; | |
border-bottom: 2px solid #667eea; | |
padding-bottom: 10px; | |
font-size: clamp(1.2rem, 3vw, 1.8rem); | |
} | |
pre { | |
background: #f8f9fa; | |
border: 1px solid #e1e4e8; | |
border-radius: 8px; | |
padding: 15px; | |
overflow-x: auto; | |
font-size: clamp(0.75rem, 2vw, 0.9rem); | |
line-height: 1.4; | |
margin: 0; | |
} | |
code { | |
color: #24292e; | |
} | |
/* Mobile-specific adjustments */ | |
@media (max-width: 768px) { | |
body { | |
padding: 10px; | |
} | |
.container { | |
padding: 20px; | |
margin: 0; | |
} | |
.controls { | |
gap: 10px; | |
justify-content: center; | |
} | |
.control-group { | |
min-width: 100px; | |
gap: 5px; | |
} | |
input[type="range"] { | |
width: 80px; | |
} | |
input[type="number"] { | |
width: 60px; | |
padding: 3px; | |
} | |
label { | |
font-size: 0.8rem; | |
} | |
pre { | |
padding: 10px; | |
font-size: 0.7rem; | |
} | |
} | |
/* Very small mobile devices */ | |
@media (max-width: 480px) { | |
.controls { | |
flex-direction: column; | |
align-items: center; | |
gap: 15px; | |
} | |
.control-group { | |
width: 100%; | |
max-width: 200px; | |
} | |
input[type="range"] { | |
width: 120px; | |
} | |
input[type="number"] { | |
width: 70px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Pentagon Flower Generator</h1> | |
<div class="preview-section"> | |
<div class="controls"> | |
<div class="control-group"> | |
<label for="circleRadius">Circle Radius</label> | |
<input type="range" id="circleRadius" min="20" max="100" value="50"> | |
<input type="number" id="circleRadiusNum" min="20" max="100" value="50"> | |
</div> | |
<div class="control-group"> | |
<label for="pentagonHeight">Pentagon Height</label> | |
<input type="range" id="pentagonHeight" min="30" max="150" value="60"> | |
<input type="number" id="pentagonHeightNum" min="30" max="150" value="60"> | |
</div> | |
<div class="control-group"> | |
<label for="numPentagons">Number of Pentagons</label> | |
<input type="range" id="numPentagons" min="3" max="20" value="10"> | |
<input type="number" id="numPentagonsNum" min="3" max="20" value="10"> | |
</div> | |
</div> | |
<div id="svgContainer"></div> | |
</div> | |
<div class="code-section"> | |
<h2>JavaScript Code</h2> | |
<pre><code>// Pentagon Flower Generator | |
// Creates a circle with pentagons radiating outward like flower petals | |
class PentagonFlower { | |
constructor(centerX, centerY, circleRadius, pentagonHeight, numPentagons = 10) { | |
this.centerX = centerX; | |
this.centerY = centerY; | |
this.circleRadius = circleRadius; | |
this.pentagonHeight = pentagonHeight; | |
this.numPentagons = numPentagons; | |
this.angleStep = 360 / this.numPentagons; | |
} | |
// Calculate pentagon vertices with curved base | |
calculatePentagonPath(angleOffset = 0) { | |
const angle = angleOffset * Math.PI / 180; | |
const baseArcAngle = this.angleStep * Math.PI / 180; | |
const halfBaseArcAngle = baseArcAngle / 2; | |
// Base arc endpoints on the circle (these define the curved base) | |
const leftArcX = this.centerX + this.circleRadius * Math.cos(angle - halfBaseArcAngle); | |
const leftArcY = this.centerY + this.circleRadius * Math.sin(angle - halfBaseArcAngle); | |
const rightArcX = this.centerX + this.circleRadius * Math.cos(angle + halfBaseArcAngle); | |
const rightArcY = this.centerY + this.circleRadius * Math.sin(angle + halfBaseArcAngle); | |
// Pentagon apex (top point) | |
const pentagonRadius = this.circleRadius + this.pentagonHeight; | |
const topX = this.centerX + pentagonRadius * Math.cos(angle); | |
const topY = this.centerY + pentagonRadius * Math.sin(angle); | |
// Side points that will be shared with adjacent pentagons | |
// These lie on the radial lines that separate adjacent pentagons | |
const leftRadialAngle = angle - halfBaseArcAngle; | |
const rightRadialAngle = angle + halfBaseArcAngle; | |
// Calculate side points along the radial lines | |
const sideRadius = this.circleRadius + this.pentagonHeight * 0.618; // Golden ratio for pentagon proportions | |
const leftSideX = this.centerX + sideRadius * Math.cos(leftRadialAngle); | |
const leftSideY = this.centerY + sideRadius * Math.sin(leftRadialAngle); | |
const rightSideX = this.centerX + sideRadius * Math.cos(rightRadialAngle); | |
const rightSideY = this.centerY + sideRadius * Math.sin(rightRadialAngle); | |
return { | |
leftArc: { x: leftArcX, y: leftArcY }, | |
rightArc: { x: rightArcX, y: rightArcY }, | |
leftSide: { x: leftSideX, y: leftSideY }, | |
rightSide: { x: rightSideX, y: rightSideY }, | |
top: { x: topX, y: topY } | |
}; | |
} | |
// Generate SVG path string for a pentagon | |
generatePentagonPath(angleOffset = 0) { | |
const points = this.calculatePentagonPath(angleOffset); | |
const largeArcFlag = this.angleStep > 180 ? 1 : 0; | |
return `M ${points.leftArc.x},${points.leftArc.y} | |
A ${this.circleRadius},${this.circleRadius} 0 ${largeArcFlag},1 ${points.rightArc.x},${points.rightArc.y} | |
L ${points.rightSide.x},${points.rightSide.y} | |
L ${points.top.x},${points.top.y} | |
L ${points.leftSide.x},${points.leftSide.y} | |
Z`; | |
} | |
// Generate complete SVG | |
generateSVG(width = 500, height = 500) { | |
const colors = ['#FF69B4', '#FF1493', '#DA70D6', '#BA55D3', '#9370DB']; | |
let svg = `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">\n`; | |
// Central circle | |
svg += ` <circle cx="${this.centerX}" cy="${this.centerY}" r="${this.circleRadius}" fill="#FFD700" stroke="#FF6B35" stroke-width="2"/>\n`; | |
// Generate pentagons | |
for (let i = 0; i < this.numPentagons; i++) { | |
const angle = i * this.angleStep; | |
const color = colors[i % colors.length]; | |
const path = this.generatePentagonPath(angle); | |
svg += ` <path d="${path}" fill="${color}" stroke="#8B008B" stroke-width="1.5"/>\n`; | |
} | |
svg += '</svg>'; | |
return svg; | |
} | |
} | |
// Usage: | |
const flower = new PentagonFlower(250, 250, 50, 60, 10); | |
const svgString = flower.generateSVG(500, 500); | |
document.getElementById('container').innerHTML = svgString;</code></pre> | |
</div> | |
</div> | |
<script> | |
// Pentagon Flower Generator Class | |
class PentagonFlower { | |
constructor(centerX, centerY, circleRadius, pentagonHeight, numPentagons = 10) { | |
this.centerX = centerX; | |
this.centerY = centerY; | |
this.circleRadius = circleRadius; | |
this.pentagonHeight = pentagonHeight; | |
this.numPentagons = numPentagons; | |
this.angleStep = 360 / this.numPentagons; | |
} | |
calculatePentagonPath(angleOffset = 0) { | |
const angle = angleOffset * Math.PI / 180; | |
const baseArcAngle = this.angleStep * Math.PI / 180; | |
const halfBaseArcAngle = baseArcAngle / 2; | |
// Base arc endpoints on the circle (these define the curved base) | |
const leftArcX = this.centerX + this.circleRadius * Math.cos(angle - halfBaseArcAngle); | |
const leftArcY = this.centerY + this.circleRadius * Math.sin(angle - halfBaseArcAngle); | |
const rightArcX = this.centerX + this.circleRadius * Math.cos(angle + halfBaseArcAngle); | |
const rightArcY = this.centerY + this.circleRadius * Math.sin(angle + halfBaseArcAngle); | |
// Pentagon apex (top point) | |
const pentagonRadius = this.circleRadius + this.pentagonHeight; | |
const topX = this.centerX + pentagonRadius * Math.cos(angle); | |
const topY = this.centerY + pentagonRadius * Math.sin(angle); | |
// Side points that will be shared with adjacent pentagons | |
// These lie on the radial lines that separate adjacent pentagons | |
const leftRadialAngle = angle - halfBaseArcAngle; | |
const rightRadialAngle = angle + halfBaseArcAngle; | |
// Calculate side points along the radial lines | |
const sideRadius = this.circleRadius + this.pentagonHeight * 0.618; // Golden ratio for pentagon proportions | |
const leftSideX = this.centerX + sideRadius * Math.cos(leftRadialAngle); | |
const leftSideY = this.centerY + sideRadius * Math.sin(leftRadialAngle); | |
const rightSideX = this.centerX + sideRadius * Math.cos(rightRadialAngle); | |
const rightSideY = this.centerY + sideRadius * Math.sin(rightRadialAngle); | |
return { | |
leftArc: { x: leftArcX, y: leftArcY }, | |
rightArc: { x: rightArcX, y: rightArcY }, | |
leftSide: { x: leftSideX, y: leftSideY }, | |
rightSide: { x: rightSideX, y: rightSideY }, | |
top: { x: topX, y: topY } | |
}; | |
} | |
generatePentagonPath(angleOffset = 0) { | |
const points = this.calculatePentagonPath(angleOffset); | |
const largeArcFlag = this.angleStep > 180 ? 1 : 0; | |
return `M ${points.leftArc.x},${points.leftArc.y} | |
A ${this.circleRadius},${this.circleRadius} 0 ${largeArcFlag},1 ${points.rightArc.x},${points.rightArc.y} | |
L ${points.rightSide.x},${points.rightSide.y} | |
L ${points.top.x},${points.top.y} | |
L ${points.leftSide.x},${points.leftSide.y} | |
Z`; | |
} | |
generateSVG(width = 500, height = 500) { | |
const colors = ['#FF69B4', '#FF1493', '#DA70D6', '#BA55D3', '#9370DB']; | |
let svg = `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">`; | |
svg += `<circle cx="${this.centerX}" cy="${this.centerY}" r="${this.circleRadius}" fill="#FFD700" stroke="#FF6B35" stroke-width="2"/>`; | |
for (let i = 0; i < this.numPentagons; i++) { | |
const angle = i * this.angleStep; | |
const color = colors[i % colors.length]; | |
const path = this.generatePentagonPath(angle); | |
svg += `<path d="${path}" fill="${color}" stroke="#8B008B" stroke-width="1.5"/>`; | |
} | |
svg += '</svg>'; | |
return svg; | |
} | |
} | |
// Initialize and render | |
let flower = new PentagonFlower(250, 250, 50, 60, 10); | |
function updateFlower() { | |
const circleRadius = parseInt(document.getElementById('circleRadius').value); | |
const pentagonHeight = parseInt(document.getElementById('pentagonHeight').value); | |
const numPentagons = parseInt(document.getElementById('numPentagons').value); | |
flower = new PentagonFlower(250, 250, circleRadius, pentagonHeight, numPentagons); | |
document.getElementById('svgContainer').innerHTML = flower.generateSVG(500, 500); | |
} | |
// Event listeners for controls | |
function setupControls() { | |
const controls = [ | |
{ slider: 'circleRadius', number: 'circleRadiusNum' }, | |
{ slider: 'pentagonHeight', number: 'pentagonHeightNum' }, | |
{ slider: 'numPentagons', number: 'numPentagonsNum' } | |
]; | |
controls.forEach(control => { | |
const slider = document.getElementById(control.slider); | |
const number = document.getElementById(control.number); | |
slider.addEventListener('input', () => { | |
number.value = slider.value; | |
updateFlower(); | |
}); | |
number.addEventListener('input', () => { | |
slider.value = number.value; | |
updateFlower(); | |
}); | |
}); | |
} | |
// Initialize | |
setupControls(); | |
updateFlower(); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Square Flower Generator</title> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
background: linear-gradient(135deg, #2196F3 0%, #21CBF3 100%); | |
min-height: 100vh; | |
box-sizing: border-box; | |
} | |
.container { | |
background: white; | |
border-radius: 15px; | |
padding: 30px; | |
box-shadow: 0 10px 30px rgba(0,0,0,0.2); | |
width: 100%; | |
box-sizing: border-box; | |
} | |
h1 { | |
text-align: center; | |
color: #333; | |
margin-bottom: 30px; | |
font-size: clamp(1.5rem, 4vw, 2.5rem); | |
} | |
.preview-section { | |
text-align: center; | |
margin-bottom: 30px; | |
} | |
.controls { | |
display: flex; | |
justify-content: center; | |
gap: 15px; | |
margin: 20px 0; | |
flex-wrap: wrap; | |
align-items: flex-start; | |
} | |
.control-group { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 8px; | |
min-width: 120px; | |
} | |
label { | |
font-weight: bold; | |
color: #555; | |
font-size: 0.9rem; | |
text-align: center; | |
} | |
input[type="range"] { | |
width: 100px; | |
min-width: 80px; | |
} | |
input[type="number"] { | |
width: 70px; | |
padding: 5px; | |
border: 2px solid #ddd; | |
border-radius: 5px; | |
text-align: center; | |
font-size: 0.9rem; | |
} | |
#svgContainer { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
margin: 20px 0; | |
} | |
#svgContainer svg { | |
max-width: 100%; | |
height: auto; | |
border: 2px solid #333; | |
border-radius: 10px; | |
background: white; | |
box-shadow: 0 5px 15px rgba(0,0,0,0.1); | |
} | |
.code-section { | |
margin-top: 30px; | |
} | |
.code-section h2 { | |
color: #333; | |
border-bottom: 2px solid #2196F3; | |
padding-bottom: 10px; | |
font-size: clamp(1.2rem, 3vw, 1.8rem); | |
} | |
pre { | |
background: #f8f9fa; | |
border: 1px solid #e1e4e8; | |
border-radius: 8px; | |
padding: 15px; | |
overflow-x: auto; | |
font-size: clamp(0.75rem, 2vw, 0.9rem); | |
line-height: 1.4; | |
margin: 0; | |
} | |
code { | |
color: #24292e; | |
} | |
/* Mobile-specific adjustments */ | |
@media (max-width: 768px) { | |
body { | |
padding: 10px; | |
} | |
.container { | |
padding: 20px; | |
margin: 0; | |
} | |
.controls { | |
gap: 10px; | |
justify-content: center; | |
} | |
.control-group { | |
min-width: 100px; | |
gap: 5px; | |
} | |
input[type="range"] { | |
width: 80px; | |
} | |
input[type="number"] { | |
width: 60px; | |
padding: 3px; | |
} | |
label { | |
font-size: 0.8rem; | |
} | |
pre { | |
padding: 10px; | |
font-size: 0.7rem; | |
} | |
} | |
/* Very small mobile devices */ | |
@media (max-width: 480px) { | |
.controls { | |
flex-direction: column; | |
align-items: center; | |
gap: 15px; | |
} | |
.control-group { | |
width: 100%; | |
max-width: 200px; | |
} | |
input[type="range"] { | |
width: 120px; | |
} | |
input[type="number"] { | |
width: 70px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Square Flower Generator</h1> | |
<div class="preview-section"> | |
<div class="controls"> | |
<div class="control-group"> | |
<label for="circleRadius">Circle Radius</label> | |
<input type="range" id="circleRadius" min="20" max="100" value="50"> | |
<input type="number" id="circleRadiusNum" min="20" max="100" value="50"> | |
</div> | |
<div class="control-group"> | |
<label for="squareHeight">Square Height</label> | |
<input type="range" id="squareHeight" min="30" max="150" value="60"> | |
<input type="number" id="squareHeightNum" min="30" max="150" value="60"> | |
</div> | |
<div class="control-group"> | |
<label for="numSquares">Number of Squares</label> | |
<input type="range" id="numSquares" min="4" max="20" value="8"> | |
<input type="number" id="numSquaresNum" min="4" max="20" value="8"> | |
</div> | |
</div> | |
<div id="svgContainer"></div> | |
</div> | |
<div class="code-section"> | |
<h2>JavaScript Code</h2> | |
<pre><code>// Square Flower Generator | |
// Creates a circle with squares radiating outward like flower petals | |
class SquareFlower { | |
constructor(centerX, centerY, circleRadius, squareHeight, numSquares = 8) { | |
this.centerX = centerX; | |
this.centerY = centerY; | |
this.circleRadius = circleRadius; | |
this.squareHeight = squareHeight; | |
this.numSquares = numSquares; | |
this.angleStep = 360 / this.numSquares; | |
} | |
// Calculate square vertices with curved base | |
calculateSquarePath(angleOffset = 0) { | |
const angle = angleOffset * Math.PI / 180; | |
const baseArcAngle = this.angleStep * Math.PI / 180; | |
const halfBaseArcAngle = baseArcAngle / 2; | |
// Base arc endpoints on the circle (these define the curved base) | |
const leftArcX = this.centerX + this.circleRadius * Math.cos(angle - halfBaseArcAngle); | |
const leftArcY = this.centerY + this.circleRadius * Math.sin(angle - halfBaseArcAngle); | |
const rightArcX = this.centerX + this.circleRadius * Math.cos(angle + halfBaseArcAngle); | |
const rightArcY = this.centerY + this.circleRadius * Math.sin(angle + halfBaseArcAngle); | |
// Square corners - calculate based on square geometry | |
const squareRadius = this.circleRadius + this.squareHeight; | |
// Left and right side points that will be shared with adjacent squares | |
const leftRadialAngle = angle - halfBaseArcAngle; | |
const rightRadialAngle = angle + halfBaseArcAngle; | |
const leftSideX = this.centerX + squareRadius * Math.cos(leftRadialAngle); | |
const leftSideY = this.centerY + squareRadius * Math.sin(leftRadialAngle); | |
const rightSideX = this.centerX + squareRadius * Math.cos(rightRadialAngle); | |
const rightSideY = this.centerY + squareRadius * Math.sin(rightRadialAngle); | |
return { | |
leftArc: { x: leftArcX, y: leftArcY }, | |
rightArc: { x: rightArcX, y: rightArcY }, | |
leftSide: { x: leftSideX, y: leftSideY }, | |
rightSide: { x: rightSideX, y: rightSideY } | |
}; | |
} | |
// Generate SVG path string for a square | |
generateSquarePath(angleOffset = 0) { | |
const points = this.calculateSquarePath(angleOffset); | |
const largeArcFlag = this.angleStep > 180 ? 1 : 0; | |
return `M ${points.leftArc.x},${points.leftArc.y} | |
A ${this.circleRadius},${this.circleRadius} 0 ${largeArcFlag},1 ${points.rightArc.x},${points.rightArc.y} | |
L ${points.rightSide.x},${points.rightSide.y} | |
L ${points.leftSide.x},${points.leftSide.y} | |
Z`; | |
} | |
// Generate complete SVG | |
generateSVG(width = 500, height = 500) { | |
const colors = ['#4FC3F7', '#29B6F6', '#03A9F4', '#0288D1', '#0277BD']; | |
let svg = `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">\n`; | |
// Central circle | |
svg += ` <circle cx="${this.centerX}" cy="${this.centerY}" r="${this.circleRadius}" fill="#FFD700" stroke="#FF6B35" stroke-width="2"/>\n`; | |
// Generate squares | |
for (let i = 0; i < this.numSquares; i++) { | |
const angle = i * this.angleStep; | |
const color = colors[i % colors.length]; | |
const path = this.generateSquarePath(angle); | |
svg += ` <path d="${path}" fill="${color}" stroke="#1565C0" stroke-width="1.5"/>\n`; | |
} | |
svg += '</svg>'; | |
return svg; | |
} | |
} | |
// Usage: | |
const flower = new SquareFlower(250, 250, 50, 60, 8); | |
const svgString = flower.generateSVG(500, 500); | |
document.getElementById('container').innerHTML = svgString;</code></pre> | |
</div> | |
</div> | |
<script> | |
// Square Flower Generator Class | |
class SquareFlower { | |
constructor(centerX, centerY, circleRadius, squareHeight, numSquares = 8) { | |
this.centerX = centerX; | |
this.centerY = centerY; | |
this.circleRadius = circleRadius; | |
this.squareHeight = squareHeight; | |
this.numSquares = numSquares; | |
this.angleStep = 360 / this.numSquares; | |
} | |
calculateSquarePath(angleOffset = 0) { | |
const angle = angleOffset * Math.PI / 180; | |
const baseArcAngle = this.angleStep * Math.PI / 180; | |
const halfBaseArcAngle = baseArcAngle / 2; | |
// Base arc endpoints on the circle (these define the curved base) | |
const leftArcX = this.centerX + this.circleRadius * Math.cos(angle - halfBaseArcAngle); | |
const leftArcY = this.centerY + this.circleRadius * Math.sin(angle - halfBaseArcAngle); | |
const rightArcX = this.centerX + this.circleRadius * Math.cos(angle + halfBaseArcAngle); | |
const rightArcY = this.centerY + this.circleRadius * Math.sin(angle + halfBaseArcAngle); | |
// Square corners - calculate based on square geometry | |
const squareRadius = this.circleRadius + this.squareHeight; | |
// Left and right side points that will be shared with adjacent squares | |
const leftRadialAngle = angle - halfBaseArcAngle; | |
const rightRadialAngle = angle + halfBaseArcAngle; | |
const leftSideX = this.centerX + squareRadius * Math.cos(leftRadialAngle); | |
const leftSideY = this.centerY + squareRadius * Math.sin(leftRadialAngle); | |
const rightSideX = this.centerX + squareRadius * Math.cos(rightRadialAngle); | |
const rightSideY = this.centerY + squareRadius * Math.sin(rightRadialAngle); | |
return { | |
leftArc: { x: leftArcX, y: leftArcY }, | |
rightArc: { x: rightArcX, y: rightArcY }, | |
leftSide: { x: leftSideX, y: leftSideY }, | |
rightSide: { x: rightSideX, y: rightSideY } | |
}; | |
} | |
generateSquarePath(angleOffset = 0) { | |
const points = this.calculateSquarePath(angleOffset); | |
const largeArcFlag = this.angleStep > 180 ? 1 : 0; | |
return `M ${points.leftArc.x},${points.leftArc.y} | |
A ${this.circleRadius},${this.circleRadius} 0 ${largeArcFlag},1 ${points.rightArc.x},${points.rightArc.y} | |
L ${points.rightSide.x},${points.rightSide.y} | |
L ${points.leftSide.x},${points.leftSide.y} | |
Z`; | |
} | |
generateSVG(width = 500, height = 500) { | |
const colors = ['#4FC3F7', '#29B6F6', '#03A9F4', '#0288D1', '#0277BD']; | |
let svg = `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">`; | |
svg += `<circle cx="${this.centerX}" cy="${this.centerY}" r="${this.circleRadius}" fill="#FFD700" stroke="#FF6B35" stroke-width="2"/>`; | |
for (let i = 0; i < this.numSquares; i++) { | |
const angle = i * this.angleStep; | |
const color = colors[i % colors.length]; | |
const path = this.generateSquarePath(angle); | |
svg += `<path d="${path}" fill="${color}" stroke="#1565C0" stroke-width="1.5"/>`; | |
} | |
svg += '</svg>'; | |
return svg; | |
} | |
} | |
// Initialize and render | |
let flower = new SquareFlower(250, 250, 50, 60, 8); | |
function updateFlower() { | |
const circleRadius = parseInt(document.getElementById('circleRadius').value); | |
const squareHeight = parseInt(document.getElementById('squareHeight').value); | |
const numSquares = parseInt(document.getElementById('numSquares').value); | |
flower = new SquareFlower(250, 250, circleRadius, squareHeight, numSquares); | |
document.getElementById('svgContainer').innerHTML = flower.generateSVG(500, 500); | |
} | |
// Event listeners for controls | |
function setupControls() { | |
const controls = [ | |
{ slider: 'circleRadius', number: 'circleRadiusNum' }, | |
{ slider: 'squareHeight', number: 'squareHeightNum' }, | |
{ slider: 'numSquares', number: 'numSquaresNum' } | |
]; | |
controls.forEach(control => { | |
const slider = document.getElementById(control.slider); | |
const number = document.getElementById(control.number); | |
slider.addEventListener('input', () => { | |
number.value = slider.value; | |
updateFlower(); | |
}); | |
number.addEventListener('input', () => { | |
slider.value = number.value; | |
updateFlower(); | |
}); | |
}); | |
} | |
// Initialize | |
setupControls(); | |
updateFlower(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment