123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- <?php
- require_once("pixel.php");
- Class XML_Node {
- private $properties = array();
- private $children = array();
- private $name;
- private $close;
- // server with php 5.3.0 has no '...' token
- //public function __construct($name = "kisses", $close = true, ... $properties) {
- public function __construct($name = "kisses", $close = true, $properties = array()) {
- //$this->add(... $properties);
- $this->add($properties);
- $this->name = $name;
- $this->close = $close;
- }
- public function append(XML_Node $child) { $this->children[] = $child; }
- //public function add(... $properties) {
- public function add($properties) {
- foreach($properties as $arr) $this->properties[] = $arr;
- }
- /* convert properties to a string, allow "late-binding", or when one wants
- * to set a property after initially setting it to another value, a good
- * example of this is a programmer "building" a wall and not knowing
- * beforehand what the final size of the wall is, part of the program
- * might calculate how tall something is based on how many bricks the
- * programmer used. This is sub-optimal, but at the moment I am not sure
- * how many bricks are needed, so unless someone can say this glut is going
- * to stay.
- *
- * -- better code would just build this string once rather than every
- * time the Class is coerced
- */
- private function propertyStr() {
- $str = array();
- foreach($this->properties as $arr) {
- // convert properties with values into HTML
- if(is_array($arr)) {
- // preserve native PHP datatype quotes, this way "1.0" is a string
- if("string" === gettype($arr[1]) || is_object($arr[1])) {
- $arr[1] = '"' . htmlentities($arr[1]) . '"';
- } else if(is_object($arr[1])) {}
- $arr = "{$arr[0]}={$arr[1]}";
- } else { /* just leave property alone */ }
- $str[] = $arr;
- }
- return (0<count($str) ?' ' :'') . implode(' ', $str);
- }
- public function __tostring() {
- $arr = array("<{$this->name}{$this->propertyStr()}>");
- foreach($this->children as $v) $arr[] = "\t" . strval($v);
- // either close comes at the end or is just a single node with terminating '/>'
- if($this->close) $arr[] = "</{$this->name}>";
- else $arr[0] = substr($arr[0], 0, -1) . " />";
- return implode(PHP_EOL, $arr);
- }
- static public function stanza($version = "1.0") {
- $s = new XML_Node("?xml", false, array(
- array("version", $version),
- array("standalone", "no")
- ));
- // XML requires '?' instead of '/' in '/>' tag terminator
- return substr($s, 0, -2) . '?>';
- }
- }
- Class Printable {
- public $value;
- public function __construct($v = 0) { $this->value = $v; }
- public function __tostring() { return strval($this->value); }
- }
- Class Coordinate {
- public $x;
- public $y;
- public function __construct($x = 0, $y = 0) {
- $this->x = $x;
- $this->y = $y;
- }
- }
- Class Coord extends Coordinate { /* alias */ }
- Class Paint {
- public $xml = array();
- private $svg;
- private $height;
- private $width;
- public function __construct() {
- $this->xml[] = XML_Node::stanza();
- // make references of the height and width properties for the SVG node
- $this->height = new Printable();
- $this->width = new Printable();
- $this->svg = new XML_Node("svg", true, array(
- // height and width as references
- array("width", /* needs to be ref */ $this->width),
- array("height", /* needs to be ref */ $this->height),
- array("version", "1.1"),
- array("xmlns", "http://www.w3.org/2000/svg"),
- ));
- // store a reference to the SVG, reference updates are tracked
- $this->xml[] = $this->svg;
- }
- private function expandCanvas($h = 0, $w = 0) {
- $this->height->value = max($this->height->value, $h);
- $this->width->value = max($this->width->value, $w);
- }
- public function addCircle(Coord $origin = NULL, Pixel $fill = NULL, $radius = 20) {
- if(NULL === $origin) $origin = new Coord();
- if(NULL === $fill) $fill = new Pixel(/*red*/ 255,0,0, 0.5);
- $y = $x = $radius;
- $circle = new XML_Node("circle", false, array(
- array("cx", strval($x + $origin->x)),
- array("cy", strval($y + $origin->y)),
- array("r", strval($radius)),
- array("fill", "#" . strval($fill))
- ));
- $this->svg->append($circle);
- // height needs to be radius * 2, assuming radius includes stroke
- $this->expandCanvas(
- /*height*/ $origin->y + ($y * 2),
- /*width*/ $origin->x + ($x * 2)
- );
- }
- public function __tostring() {
- $s = "";
- foreach($this->xml as $n) $s .= strval($n) . PHP_EOL;
- return $s;
- }
- }
- /*
- header("Content-Type: application: xhtml+xml");
- $test = new Paint();
- $test->addCircle(new Coord(0,0));
- $test->addCircle(new Coord(40,0), new Pixel(255,255,0));
- echo $test;
- */
|