calc/src/Graph/Graph.php
2025-07-11 16:39:35 +02:00

126 lines
3.6 KiB
PHP

<?php
namespace PSC\Library\Calc\Graph;
use PSC\Library\Calc\Model\Part;
use PSC\Library\Calc\Model\PartCollection;
use SVG\Nodes\Shapes\SVGRect;
use SVG\Nodes\Structures\SVGDocumentFragment;
use SVG\Nodes\Texts\SVGText;
use SVG\Nodes\Texts\SVGTSpan;
use SVG\SVG;
class Graph
{
protected PartCollection $calcFormel;
protected Parser $parser;
protected Calc $calc;
public function __construct(string $formulas = '', string $params = '')
{
$this->calcFormel = new PartCollection();
$this->parser = new Parser($formulas, $params);
$this->calc = new Calc($params, $formulas);
}
public function addCalcFormel(Part $formel): void
{
$this->calcFormel->addPart($formel);
}
public function addPart(Part $part): void
{
$this->parser->addPart($part);
}
private function build(): bool
{
$this->parser->parseInternals();
foreach ($this->calcFormel->getData() as $formel) {
$this->parser->parse($formel);
}
foreach ($this->calcFormel->getData() as $formel) {
$this->calc->calc($formel);
}
return true;
}
public function getSum(): float
{
return round(array_reduce($this->calcFormel->getData(), fn($sum, $item) => $sum + $item->getResult(), 0), 2);
}
public function generateJsonGraph(): string
{
$this->build();
$json = [];
foreach ($this->calcFormel->getData() as $part) {
$json[] = $part->toArray();
}
return json_encode($json);
}
public function generateSVGGraph(): string
{
$image = new SVG(1000, 1000);
$doc = $image->getDocument();
$doc->setStyle('background-color', '#ffffff');
$bg = new SVGRect(0, 0, 1000, 1000);
$bg->setAttribute('fill', '#ffffff');
$doc->addChild($bg);
$x = 20;
$y = 0;
foreach ($this->calcFormel as $formel) {
$y = $this->renderSubPart($x, $y, $doc, $formel);
}
return $image->toXMLString();
}
private function renderSubPart(int $x, int $y, SVGDocumentFragment $doc, Part $part): int
{
$y = $y + 20;
if (count($part->getChildren()) > 0) {
$textC = new SVGText('', $x, $y);
$span1 = new SVGTSpan();
$span1->setValue(sprintf('%s', $part->getName()));
$textC->addChild($span1);
$pattern = '/(\$[FPV][a-zA-Z0-9]+\$[FPV])/';
$parts = preg_split($pattern, $part->getUnparsed(), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach ($parts as $subPart) {
$child = $part->getChildrenByName($subPart);
if ($child) {
$span1 = new SVGTSpan();
$span1->setValue(sprintf('%s (%s)', $subPart, $child->getResult()));
$span1->setAttribute('dx', 10);
$span1->setAttribute('fill', $child->getColor());
$textC->addChild($span1);
$x = $x + 20;
$y = $this->renderSubPart($x, $y, $doc, $child);
} else {
$span1 = new SVGTSpan();
$span1->setValue($subPart);
$span1->setAttribute('dx', 10);
$textC->addChild($span1);
}
}
} else {
$textC = new SVGText('', $x, $y);
$span1 = new SVGTSpan();
$span1->setValue($part->getUnparsed());
$span1->setAttribute('dx', 10);
$textC->addChild($span1);
}
$doc->addChild($textC);
return $y;
}
}