1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > Islamic Tile Pattern</ title >
7+ < style >
8+ body {
9+ margin : 0 ;
10+ padding : 0 ;
11+ overflow : hidden;
12+ background : # f5e6d3 ;
13+ }
14+ canvas {
15+ display : block;
16+ }
17+ </ style >
18+ </ head >
19+ < body >
20+ < canvas id ="canvas "> </ canvas >
21+ < script >
22+ const canvas = document . getElementById ( 'canvas' ) ;
23+ const ctx = canvas . getContext ( '2d' ) ;
24+
25+ canvas . width = window . innerWidth ;
26+ canvas . height = window . innerHeight ;
27+
28+ const COLORS = {
29+ cream : '#f5e6d3' ,
30+ darkBlue : '#4a6b8a' ,
31+ lightBlue : '#6a88a8' ,
32+ darkGreen : '#3d5f52' ,
33+ lightGreen : '#5a7a6a' ,
34+ brown : '#9b7f57' ,
35+ darkBrown : '#6b5738' ,
36+ black : '#2a2a2a' ,
37+ gold : '#c8a870'
38+ } ;
39+
40+ const TRIANGLE_COLORS = [
41+ COLORS . darkBlue , COLORS . lightBlue , COLORS . darkGreen ,
42+ COLORS . lightGreen , COLORS . brown , COLORS . darkBrown , COLORS . black
43+ ] ;
44+
45+ const STAR_COLORS = [
46+ COLORS . darkBlue , COLORS . lightBlue , COLORS . darkGreen ,
47+ COLORS . lightGreen , COLORS . brown , COLORS . gold , COLORS . black
48+ ] ;
49+
50+ const TRIANGLE_SIDE_LENGTH = 120 ;
51+ const TRIANGLE_HEIGHT = TRIANGLE_SIDE_LENGTH * Math . sqrt ( 3 ) / 2 ;
52+ const HALF_SIDE_LENGTH = TRIANGLE_SIDE_LENGTH / 2 ;
53+ const SEMICIRCLE_AMPLITUDE_FACTOR = 0.7 ;
54+ const SEMICIRCLE_SEGMENTS = 50 ;
55+ const STAR_ROTATION_OFFSET = Math . PI / 6 ;
56+
57+ const INRADIUS = TRIANGLE_SIDE_LENGTH / ( 2 * Math . sqrt ( 3 ) ) ;
58+ const HEXAGON_RADIUS = INRADIUS * 0.6 ;
59+ const STAR_OUTER_RADIUS = INRADIUS * 0.66 ;
60+ const STAR_INNER_RADIUS = STAR_OUTER_RADIUS * 0.5 ;
61+
62+ const SEMICIRCLE_DIAMETER = TRIANGLE_SIDE_LENGTH / 2 ;
63+ const SEMICIRCLE_RADIUS = SEMICIRCLE_DIAMETER / 2 ;
64+
65+ const TRIANGLE_COLOR_COUNT = TRIANGLE_COLORS . length ;
66+ const STAR_COLOR_COUNT = STAR_COLORS . length ;
67+
68+ const precomputedStarAngles = [ ] ;
69+ const precomputedStarRadii = [ ] ;
70+ for ( let i = 0 ; i < 12 ; i ++ ) {
71+ precomputedStarAngles [ i ] = ( Math . PI / 6 ) * i - Math . PI / 2 + STAR_ROTATION_OFFSET ;
72+ precomputedStarRadii [ i ] = i % 2 === 0 ? STAR_OUTER_RADIUS : STAR_INNER_RADIUS ;
73+ }
74+
75+ const precomputedHexagonAngles = [ ] ;
76+ for ( let i = 0 ; i < 6 ; i ++ ) {
77+ precomputedHexagonAngles [ i ] = ( Math . PI / 3 ) * i ;
78+ }
79+
80+ const precomputedSemicircleProgress = new Float32Array ( SEMICIRCLE_SEGMENTS ) ;
81+ for ( let i = 0 ; i < SEMICIRCLE_SEGMENTS ; i ++ ) {
82+ precomputedSemicircleProgress [ i ] = ( i + 1 ) / SEMICIRCLE_SEGMENTS ;
83+ }
84+
85+ function getDiagonalColorIndex ( diagonal , totalColors ) {
86+ return ( ( diagonal % totalColors ) + totalColors ) % totalColors ;
87+ }
88+
89+ function drawSixPointedStar ( centerX , centerY , color ) {
90+ ctx . fillStyle = color ;
91+ ctx . beginPath ( ) ;
92+
93+ let x = centerX + Math . cos ( precomputedStarAngles [ 0 ] ) * precomputedStarRadii [ 0 ] ;
94+ let y = centerY + Math . sin ( precomputedStarAngles [ 0 ] ) * precomputedStarRadii [ 0 ] ;
95+ ctx . moveTo ( x , y ) ;
96+
97+ for ( let i = 1 ; i < 12 ; i ++ ) {
98+ x = centerX + Math . cos ( precomputedStarAngles [ i ] ) * precomputedStarRadii [ i ] ;
99+ y = centerY + Math . sin ( precomputedStarAngles [ i ] ) * precomputedStarRadii [ i ] ;
100+ ctx . lineTo ( x , y ) ;
101+ }
102+
103+ ctx . closePath ( ) ;
104+ ctx . fill ( ) ;
105+ }
106+
107+ function drawRegularHexagon ( centerX , centerY , color ) {
108+ ctx . fillStyle = color ;
109+ ctx . beginPath ( ) ;
110+
111+ let x = centerX + Math . cos ( precomputedHexagonAngles [ 0 ] ) * HEXAGON_RADIUS ;
112+ let y = centerY + Math . sin ( precomputedHexagonAngles [ 0 ] ) * HEXAGON_RADIUS ;
113+ ctx . moveTo ( x , y ) ;
114+
115+ for ( let i = 1 ; i < 6 ; i ++ ) {
116+ x = centerX + Math . cos ( precomputedHexagonAngles [ i ] ) * HEXAGON_RADIUS ;
117+ y = centerY + Math . sin ( precomputedHexagonAngles [ i ] ) * HEXAGON_RADIUS ;
118+ ctx . lineTo ( x , y ) ;
119+ }
120+
121+ ctx . closePath ( ) ;
122+ ctx . fill ( ) ;
123+ }
124+
125+ function drawSemiCircularWaveSide ( x1 , y1 , x2 , y2 ) {
126+ const dx = x2 - x1 ;
127+ const dy = y2 - y1 ;
128+ const invLength = 1 / Math . sqrt ( dx * dx + dy * dy ) ;
129+
130+ const unitX = dx * invLength ;
131+ const unitY = dy * invLength ;
132+ const perpX = - unitY ;
133+ const perpY = unitX ;
134+
135+ const midX = ( x1 + x2 ) * 0.5 ;
136+ const midY = ( y1 + y2 ) * 0.5 ;
137+
138+ const halfDx = ( midX - x1 ) ;
139+ const halfDy = ( midY - y1 ) ;
140+
141+ for ( let i = 0 ; i < SEMICIRCLE_SEGMENTS ; i ++ ) {
142+ const t = precomputedSemicircleProgress [ i ] ;
143+
144+ let pointX , pointY , height ;
145+
146+ if ( t <= 0.5 ) {
147+ const s = t * 2 ;
148+ const alongX = x1 + halfDx * s ;
149+ const alongY = y1 + halfDy * s ;
150+ const distFromCenter = ( s - 0.5 ) * SEMICIRCLE_DIAMETER ;
151+ height = Math . sqrt ( SEMICIRCLE_RADIUS * SEMICIRCLE_RADIUS - distFromCenter * distFromCenter ) * SEMICIRCLE_AMPLITUDE_FACTOR ;
152+
153+ pointX = alongX + perpX * height ;
154+ pointY = alongY + perpY * height ;
155+ } else {
156+ const s = ( t - 0.5 ) * 2 ;
157+ const alongX = midX + halfDx * s ;
158+ const alongY = midY + halfDy * s ;
159+ const distFromCenter = ( s - 0.5 ) * SEMICIRCLE_DIAMETER ;
160+ height = Math . sqrt ( SEMICIRCLE_RADIUS * SEMICIRCLE_RADIUS - distFromCenter * distFromCenter ) * SEMICIRCLE_AMPLITUDE_FACTOR ;
161+
162+ pointX = alongX - perpX * height ;
163+ pointY = alongY - perpY * height ;
164+ }
165+
166+ ctx . lineTo ( pointX , pointY ) ;
167+ }
168+ }
169+
170+ function drawTriangleWithCurvedSides ( x1 , y1 , x2 , y2 , x3 , y3 , color ) {
171+ ctx . beginPath ( ) ;
172+ ctx . moveTo ( x1 , y1 ) ;
173+ drawSemiCircularWaveSide ( x1 , y1 , x2 , y2 ) ;
174+ drawSemiCircularWaveSide ( x2 , y2 , x3 , y3 ) ;
175+ drawSemiCircularWaveSide ( x3 , y3 , x1 , y1 ) ;
176+ ctx . closePath ( ) ;
177+ ctx . fillStyle = color ;
178+ ctx . fill ( ) ;
179+ }
180+
181+ function drawColoredTriangleWithHexagon ( baseX , baseY , diagonal ) {
182+ const x1 = baseX ;
183+ const y1 = baseY ;
184+ const x2 = baseX + TRIANGLE_SIDE_LENGTH ;
185+ const y2 = baseY ;
186+ const x3 = baseX + HALF_SIDE_LENGTH ;
187+ const y3 = baseY + TRIANGLE_HEIGHT ;
188+
189+ const colorIndex = getDiagonalColorIndex ( diagonal , TRIANGLE_COLOR_COUNT ) ;
190+ drawTriangleWithCurvedSides ( x1 , y1 , x2 , y2 , x3 , y3 , TRIANGLE_COLORS [ colorIndex ] ) ;
191+
192+ const centroidX = ( x1 + x2 + x3 ) / 3 ;
193+ const centroidY = ( y1 + y2 + y3 ) / 3 ;
194+
195+ drawRegularHexagon ( centroidX , centroidY , COLORS . cream ) ;
196+ }
197+
198+ function drawWhiteTriangleWithStar ( baseX , baseY , diagonal ) {
199+ const x1 = baseX + HALF_SIDE_LENGTH ;
200+ const y1 = baseY ;
201+ const x2 = baseX ;
202+ const y2 = baseY + TRIANGLE_HEIGHT ;
203+ const x3 = baseX + TRIANGLE_SIDE_LENGTH ;
204+ const y3 = baseY + TRIANGLE_HEIGHT ;
205+
206+ drawTriangleWithCurvedSides ( x1 , y1 , x2 , y2 , x3 , y3 , COLORS . cream ) ;
207+
208+ const centroidX = ( x1 + x2 + x3 ) / 3 ;
209+ const centroidY = ( y1 + y2 + y3 ) / 3 ;
210+
211+ const starColorIndex = getDiagonalColorIndex ( diagonal + 1 , STAR_COLOR_COUNT ) ;
212+ drawSixPointedStar ( centroidX , centroidY , STAR_COLORS [ starColorIndex ] ) ;
213+ }
214+
215+ function drawCompletePattern ( ) {
216+ ctx . fillStyle = COLORS . cream ;
217+ ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
218+
219+ const columnCount = Math . ceil ( canvas . width / TRIANGLE_SIDE_LENGTH ) + 2 ;
220+ const rowCount = Math . ceil ( canvas . height / TRIANGLE_HEIGHT ) + 2 ;
221+
222+ for ( let row = - 1 ; row < rowCount ; row ++ ) {
223+ const horizontalOffset = ( row & 1 ) * HALF_SIDE_LENGTH ;
224+ const yPosition = row * TRIANGLE_HEIGHT ;
225+ const diagonal = row ;
226+
227+ for ( let col = - 1 ; col < columnCount ; col ++ ) {
228+ const coloredTriangleX = col * TRIANGLE_SIDE_LENGTH + horizontalOffset ;
229+ drawColoredTriangleWithHexagon ( coloredTriangleX , yPosition , diagonal - col ) ;
230+
231+ const whiteTriangleX = coloredTriangleX + HALF_SIDE_LENGTH ;
232+ drawWhiteTriangleWithStar ( whiteTriangleX , yPosition , diagonal - col ) ;
233+ }
234+ }
235+ }
236+
237+ function handleResize ( ) {
238+ canvas . width = window . innerWidth ;
239+ canvas . height = window . innerHeight ;
240+ drawCompletePattern ( ) ;
241+ }
242+
243+ drawCompletePattern ( ) ;
244+ window . addEventListener ( 'resize' , handleResize ) ;
245+ </ script >
246+ </ body >
247+ </ html >
0 commit comments