| 
<?php
 /**
 * This example uses a dartboard to demonstrate the advantages of using polar
 * coordinates when constructing objects based on circle calculations.
 *
 * In addition, the use of user-defined attributes is shown, for example to react
 * on user interactions.
 *
 * @author Stefanius <[email protected]>
 * @copyright GPLv3 License - see the LICENSE file for details
 */
 
 declare(strict_types=1);
 
 include '../autoloader.php';
 
 use SKien\SVGCreator\SVG;
 use SKien\SVGCreator\SVGElement;
 use SKien\SVGCreator\SVGGroup;
 use SKien\SVGCreator\Shapes\SVGEllipse;
 use SKien\SVGCreator\Shapes\SVGPath;
 use SKien\SVGCreator\Shapes\SVGRect;
 use SKien\SVGCreator\Text\SVGText;
 
 $iSVGWidth = 800;
 $iSVGHeight = 600;
 
 $oSVG = new SVG();
 $oSVG->setPrettyOutput(true);
 $oSVG->setSize($iSVGWidth, $iSVGHeight);
 
 $oSVG->addStyleDef(".grid {stroke: #999; stroke-width: 1; stroke-dasharray: 1 2;}");
 $oSVG->addStyleDef("text {fill: white; text-anchor: middle; dominant-baseline: middle; font-weight: 400; font-style: normal; font-family: 'Arial';}");
 $oSVG->addStyleDef(".seg1 {fill: darkgreen; stroke: #fff; stroke-width: 2;}");
 $oSVG->addStyleDef(".seg2 {fill: red; stroke: #fff; stroke-width: 2;}");
 $oSVG->addStyleDef(".seg3 {fill: black; stroke: #fff; stroke-width: 2;}");
 $oSVG->addStyleDef(".seg4 {fill: #F5DEB3; stroke: #fff; stroke-width: 2;}");
 $oSVG->addStyleDef(".seg1:hover, .seg2:hover, .seg3:hover, .seg4:hover {fill: blue;}");
 
 $oSVG->add(new SVGRect(0, 0, $iSVGWidth, $iSVGHeight, 'fill: black;'));
 
 $aScore = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5];
 
 $radius = $iSVGWidth > $iSVGHeight ? $iSVGHeight / 2 : $iSVGWidth / 2;
 $oBoard = new SVGGroup('board');
 $degree = -99;      // starting point is -99 degrees (-90 degrees minus half segment angle)
 $r = [0.05 * $radius, 0.1 * $radius, 0.39 * $radius, 0.45 * $radius, 0.74 * $radius, 0.8 * $radius, 0.9 * $radius];
 for ($i = 0; $i < 20; $i++) {
 // Inner single-counting segments
 addHotSpot(createSegment($i % 2 == 0 ? 'seg3' : 'seg4', $degree, $r[1], $r[2]), $aScore[$i]);
 // Inner wreath containing the triple counting fields
 addHotSpot(createSegment($i % 2 == 0 ? 'seg2' : 'seg1', $degree, $r[2], $r[3]), 3 * $aScore[$i], 'Tripple ' . $aScore[$i], 'T' . $aScore[$i]);
 // Outer single-counting segments
 addHotSpot(createSegment($i % 2 == 0 ? 'seg3' : 'seg4', $degree, $r[3], $r[4]), $aScore[$i]);
 // Outer wreath containing the double counting fields
 addHotSpot(createSegment($i % 2 == 0 ? 'seg2' : 'seg1', $degree, $r[4], $r[5]), 2 * $aScore[$i], 'Double ' . $aScore[$i], 'D' . $aScore[$i]);
 
 // Score around the board
 $oText = $oBoard->add(new SVGText(0, -$r[6], (string) $aScore[$i]));
 $oText->setAttribute('font-size', 0.15 * $radius);
 $oText->rotate($degree + 99);
 
 $degree += 18; // (360 / 20)
 }
 addHotSpot(new SVGEllipse(0, 0, $r[1], $r[1], 'seg1'), 25, 'Bull', '25');
 addHotSpot(new SVGEllipse(0, 0, $r[0], $r[0], 'seg2'), 50, 'Bulls Eye', '50');
 
 $oBoard->translate($iSVGWidth / 2, $iSVGHeight / 2);
 $oSVG->add($oBoard);
 
 /**
 * Creates a subsegment with the specified values.
 * The subsegment is created from the inner to the outer radius, starting at the
 * specified angle in degrees and ending at the specified angle plus 18 (360 / 20).
 * The specified class is set for the display style.
 * @param string $strClass
 * @param float $degree
 * @param float $rInner
 * @param float $rOuter
 * @return SVGPath
 */
 function createSegment(string $strClass, float $degree, float $rInner, float $rOuter) : SVGPath
 {
 global $oSVG;
 
 [$x1, $y1] = $oSVG->fromPolar($rInner, $degree);
 [$x2, $y2] = $oSVG->fromPolar($rInner, $degree + 18);
 [$x3, $y3] = $oSVG->fromPolar($rOuter, $degree + 18);
 [$x4, $y4] = $oSVG->fromPolar($rOuter, $degree);
 
 $oPath = new SVGPath($strClass);
 $oPath->moveTo($x1, $y1);
 $oPath->arcAt($rInner, $rInner, 0, 0, 1, $x2, $y2);
 $oPath->lineTo($x3, $y3);
 $oPath->arcAt($rOuter, $rOuter, 0, 0, 0, $x4, $y4);
 
 return $oPath;
 }
 
 /**
 * Adds the element to the board and set the user defined data attributes that
 * can be evluated e.g. within a `click` eventhandler to display or process the
 * clicked score.
 * @param SVGElement $oHotSpot
 * @param int $iScore
 * @param string $strText
 * @param string $strShort
 */
 function addHotSpot(SVGElement $oHotSpot, int $iScore, string $strText = null, string $strShort = null) : void
 {
 global $oBoard;
 $oBoard->add($oHotSpot);
 $oHotSpot->setAttribute('data-score', $iScore);
 $oHotSpot->setAttribute('data-text', $strText ?? (string) $iScore);
 $oHotSpot->setAttribute('data-short', $strShort ?? (string) $iScore);
 }
 ?>
 <!DOCTYPE HTML>
 <html lang="de-de">
 <head>
 <script>
 function onLoad()
 {
 var oBoard = document.getElementById('dartboard');
 oBoard.addEventListener('click', onBoardClicked);
 }
 
 function onBoardClicked(evt)
 {
 var strMsg = "Dartboard clicked\n";
 if (evt.srcElement.getAttribute('data-score') !== null) {
 strMsg += 'Score: ' + evt.srcElement.getAttribute('data-score') + ' (' + evt.srcElement.getAttribute('data-text') + ')';
 } else {
 strMsg += 'Outside - no score :-(';
 }
 alert(strMsg);
 }
 </script>
 </head>
 <body onload="onLoad()">
 <div id="dartboard">
 <?php echo $oSVG->getSVG(); ?>
 </div>
 </body>
 |