By: walter
Date: 2015-03-05
Time: 00:19
|
Charts inside blocks
Hi,
I really need to accomplish that. I am digging into the sources but until now I got no success.
To add graphs dynamically you need to add the rId reference to word/_rels/document.xml.rels, add the file to word/charts, add an Override to [Content_Types].xml and the <drawing> in word/document.xml.
My problem is the last step, needed to point to the graph, after the whole merging of the file. Or adapt the MergeBlock function for doing that for me.
Is there a way to get the final XML after all merging and search for a string and replace with my template? I think this could be enough for my issue, since I could merge ids for my graphs and then look for them, replacing with the appropriate XML.
Thanks in advance.
|
By: walter
Date: 2015-03-05
Time: 20:20
|
Re: Charts inside blocks
I solved my problem. It is not a very dynamic solution, but can be very handy in some cases.
Using it goes like this: You add the charts at the moment you call the MergeBlock commands. Something like this
$TBS->AddChart(array(
'title' => $fNames[$key],
'series' => array(
array(
'title' => $fNames[$key],
'x' => $x,
'y' => $y
)
)
));
|
Besides that, I select the place the chart will be inserted merging a simple block, like this
$TBS->MergeBlock('a',array(
array(
'show' => '1',
'caption' => 'Lorem Ips',
'graph' => 'chr1',
)
));
|
Note that the chr1 is exactly what is going to be placed on the final file. Then starts the awesome!
I extended the classes (TBS and OpenTBS) and overloaded some methods:
TBS:
class CustomTbs extends clsTinyButStrong
{
public $charts = array();
public $lastChart = 0;
public function AddChart($props){
$this->lastChart++;
$this->charts['chr'.$this->lastChart] = $props;
}
}
|
OpenTBS:
class CustomOpenTbs extends clsOpenTBS
{
function chartDocumentCall($id) {
$n = substr($id, 3);
return '<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="29E87212" wp14:editId="01E1C7C3"><wp:extent cx="5486400" cy="3200400"/><wp:effectExtent l="0" t="0" r="25400" b="25400"/><wp:docPr id="' . $n . '" name="Chart ' . $n . '"/><wp:cNvGraphicFramePr/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"><c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="' . $id . '"/></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>';
}
function chartTemplate($chart){
$s = '';
$i = 0;
foreach ($chart['series'] as $serie) {
$s .= $this->chartSeries($i, $serie['title'], $serie['x'], $serie['y']);
$i++;
}
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<c:chartSpace xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><c:date1904 val="0"/><c:lang val="en-US"/><c:roundedCorners val="0"/><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice Requires="c14" xmlns:c14="http://schemas.microsoft.com/office/drawing/2007/8/2/chart"><c14:style val="118"/></mc:Choice><mc:Fallback><c:style val="18"/></mc:Fallback></mc:AlternateContent><c:chart><c:title><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:pPr><a:defRPr/></a:pPr><a:r><a:rPr lang="en-US"/><a:t>'.$chart['title'].'</a:t></a:r></a:p></c:rich></c:tx><c:layout/><c:overlay val="0"/></c:title><c:autoTitleDeleted val="0"/><c:plotArea><c:layout/><c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>'.$s.'<c:dLbls><c:showLegendKey val="0"/><c:showVal val="0"/><c:showCatName val="0"/><c:showSerName val="0"/><c:showPercent val="0"/><c:showBubbleSize val="0"/></c:dLbls><c:axId val="2123714840"/><c:axId val="2125151656"/></c:scatterChart><c:valAx><c:axId val="2123714840"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:delete val="0"/><c:axPos val="b"/><c:numFmt formatCode="General" sourceLinked="1"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crossAx val="2125151656"/><c:crosses val="autoZero"/><c:crossBetween val="midCat"/></c:valAx><c:valAx><c:axId val="2125151656"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:delete val="0"/><c:axPos val="l"/><c:numFmt formatCode="General" sourceLinked="1"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crossAx val="2123714840"/><c:crosses val="autoZero"/><c:crossBetween val="midCat"/></c:valAx></c:plotArea><c:legend><c:legendPos val="b"/><c:layout/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/><c:showDLblsOverMax val="0"/></c:chart><c:spPr><a:ln><a:noFill/></a:ln></c:spPr></c:chartSpace>';
}
function InsertCharts() {
$TBS =& $this->TBS;
foreach ($TBS->charts as $rid=>$chart) {
$this->OpenXML_Rels_AddNewChartRid('word/document.xml', 'charts/', $rid);
}
}
function chartSeries($id, $title, $xValues, $yValues) {
$nx = count($xValues);
$ny = count($yValues);
$x = '';
$i = 0;
foreach ($xValues as $v) {
$x .= '<c:pt idx="'.$i.'"><c:v>'.$v.'</c:v></c:pt>';
$i++;
}
$y = '';
$i = 0;
foreach ($yValues as $v) {
$y .= '<c:pt idx="'.$i.'"><c:v>'.$v.'</c:v></c:pt>';
$i++;
}
return '<c:ser><c:idx val="'.$id.'"/><c:order val="'.$id.'"/><c:tx><c:v>'.$title.'</c:v></c:tx><c:spPr><a:ln w="47625"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val="circle"/><c:size val="4"/><c:spPr><a:solidFill><a:schemeClr val="tx1"/></a:solidFill><a:ln><a:solidFill><a:schemeClr val="tx1"/></a:solidFill></a:ln></c:spPr></c:marker><c:trendline><c:trendlineType val="linear"/><c:dispRSqr val="0"/><c:dispEq val="0"/></c:trendline><c:xVal><c:numLit><c:formatCode>General</c:formatCode><c:ptCount val="'.$nx.'"/>'.$x.'</c:numLit></c:xVal><c:yVal><c:numLit><c:formatCode>General</c:formatCode><c:ptCount val="'.$ny.'"/>'.$y.'</c:numLit></c:yVal><c:smooth val="0"/></c:ser>';
}
function BeforeShow(&$Render, $File='') {
$TBS =& $this->TBS;
$this->InsertCharts();
if ($this->OpenXmlRid!==false) $this->OpenXML_Rels_CommitNewChartRids($TBS); //Moved for merging the chart call in document.xml
if ($this->ArchFile==='') {
return $this->RaiseError('Command Show() cannot be processed because no archive is opened.');
}
if ($TBS->_Mode!=0) return; // If we are in subtemplate mode, the we use the TBS default process
if ($this->TbsSystemCredits) {
$this->Misc_EditCredits("OpenTBS " . $this->Version, true, true);
}
$this->TbsStorePark(); // Save the current loaded subfile if any
$TBS->Plugin(-4); // deactivate other plugins
$Debug = (($Render & OPENTBS_DEBUG_XML)==OPENTBS_DEBUG_XML);
if ($Debug) $this->DebugLst = array();
$TbsShow = (($Render & OPENTBS_DEBUG_AVOIDAUTOFIELDS)!=OPENTBS_DEBUG_AVOIDAUTOFIELDS);
switch ($this->ExtEquiv) {
case 'ods': $this->OpenDoc_SheetSlides_DeleteAndDisplay(true); break;
case 'odp': $this->OpenDoc_SheetSlides_DeleteAndDisplay(false); break;
case 'xlsx': $this->MsExcel_SheetDeleteAndDisplay(); break;
case 'pptx': $this->MsPowerpoint_SlideDelete(); break;
}
$explicitRef = ($TBS->OtbsMsExcelExplicitRef && ($this->ExtEquiv==='xlsx'));
// Merges all modified subfiles
$idx_lst = array_keys($this->TbsStoreLst);
foreach ($idx_lst as $idx) {
$TBS->Source = $this->TbsStoreLst[$idx]['src'];
$onshow = $this->TbsStoreLst[$idx]['onshow'];
unset($this->TbsStoreLst[$idx]); // save memory space
$TBS->OtbsCurrFile = $this->TbsGetFileName($idx); // usefull for TbsPicAdd()
$this->TbsCurrIdx = $idx; // usefull for debug mode
if ($TbsShow && $onshow) $TBS->Show(TBS_NOTHING);
if ($this->ExtEquiv == 'docx') {
$this->MsWord_RenumDocPr($TBS->Source);
}
if ($explicitRef && (!isset($this->MsExcel_KeepRelative[$idx])) ) {
$this->MsExcel_ConvertToExplicit($TBS->Source);
}
if ($Debug) $this->DebugLst[$this->TbsGetFileName($idx)] = $TBS->Source;
$this->FileReplace($idx, $TBS->Source, TBSZIP_STRING, $TBS->OtbsAutoUncompress);
}
$TBS->Plugin(-10); // reactivate other plugins
$this->TbsCurrIdx = false;
if ($this->OpenXmlCTypes!==false) $this->OpenXML_CTypesCommit($Debug); // Commit special OpenXML features if any
if ($this->OpenDocManif!==false) $this->OpenDoc_ManifestCommit($Debug); // Commit special OpenDocument features if any
//if ($this->OpenXmlRid!==false) $this->OpenXML_Rels_CommitNewRids($Debug); // Must be done also after the loop because some Rid can be added with [onshow]
//if ($this->OpenXmlRid!==false) $this->OpenXML_Rels_CommitNewChartRids($Debug); // Must be done also after the loop because some Rid can be added with [onshow]
if ($TBS->OtbsGarbageCollector) {
if ($this->ExtType=='openxml') $this->OpenMXL_GarbageCollector();
}
if ( ($TBS->ErrCount>0) && (!$TBS->NoErr) && (!$Debug)) {
$TBS->meth_Misc_Alert('Show() Method', 'The output is cancelled by the OpenTBS plugin because at least one error has occured.');
exit;
}
if ($Debug) {
// Do the debug even if other options are used
$this->TbsDebug_Merge(true, false);
} elseif (($Render & TBS_OUTPUT)==TBS_OUTPUT) { // notice that TBS_OUTPUT = OPENTBS_DOWNLOAD
// download
$ContentType = (isset($this->ExtInfo['ctype'])) ? $this->ExtInfo['ctype'] : '';
$this->Flush($Render, $File, $ContentType); // $Render is used because it can contain options OPENTBS_DOWNLOAD and OPENTBS_NOHEADER.
$Render = $Render - TBS_OUTPUT; //prevent TBS from an extra output.
} elseif(($Render & OPENTBS_FILE)==OPENTBS_FILE) {
// to file
$this->Flush(TBSZIP_FILE, $File);
} elseif(($Render & OPENTBS_STRING)==OPENTBS_STRING) {
// to string
$this->Flush(TBSZIP_STRING);
$TBS->Source = $this->OutputSrc;
$this->OutputSrc = '';
}
if (($Render & TBS_EXIT)==TBS_EXIT) {
$this->Close();
exit;
}
return false; // cancel the default Show() process
}
function OpenXML_Rels_AddNewChartRid($DocPath, $TargetDir, $rid) {
$o = $this->OpenXML_Rels_GetObj($DocPath, $TargetDir);
$Target = $TargetDir.$rid.'.xml';
if (isset($o->RidLst[$Target])) return $o->RidLst[$Target];
// Add the Rid in the information
//$NewRid = 'chr'.(1+count($o->RidNew));
$NewRid = $rid;
$o->RidLst[$Target] = $NewRid;
$o->RidNew[$Target] = $NewRid;
//$this->IdxToCheck[$o->ParentIdx] = $o->FicIdx;
return $NewRid;
}
function OpenXML_Rels_CommitNewChartRids (&$TBS, $Debug=false) {
foreach ($this->OpenXmlRid as $doc => $o) {
if (count($o->RidNew)>0) {
// search position for insertion
$p = strpos($o->FicTxt, '</Relationships>');
if ($p===false) return $this->RaiseError("(OpenXML) closing tag </Relationships> not found in subfile ".$o->FicPath);
// build the string to insert
$x = '';
$r = '';
foreach ($o->RidNew as $target=>$rid) {
$x .= '<Relationship Id="'.$rid.'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" Target="'.$target.'"/>';
//insert pointer to graph in document
$TBS->Source = str_replace('<w:r><w:t>' . $rid . '</w:t></w:r>', $this->chartDocumentCall($rid), $TBS->Source);
//inser file in charts/
$this->FileAdd('word/' . $target, $this->chartTemplate($TBS->charts[$rid]));
$r .= '<Override PartName="/word/' . $target . '" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/>';
}
//insert content types
$file = '[Content_Types].xml';
$idx = $this->FileGetIdx($file);
$Txt = $this->FileRead($idx, true);
$posBeg = 0;
$loc = clsTbsXmlLoc::FindStartTag($Txt, 'Types', $posBeg);
$loc->FindEndTag();
$Txt = substr_replace($Txt, $r, $loc->PosEnd - 7, 0);
$this->FileReplace($idx, $Txt);
// insert in references
$o->FicTxt = substr_replace($o->FicTxt, $x, $p, 0);
// save
if ($o->FicType==1) {
$this->FileAdd($o->FicPath, $o->FicTxt);
} else {
$this->FileReplace($o->FicIdx, $o->FicTxt);
}
// debug mode
if ($Debug) $this->DebugLst[$o->FicPath] = $o->FicTxt;
$this->OpenXmlRid[$doc]->RidNew = array(); // Erase the Rid done because there can be another commit
}
}
}
}
|
The magic happens on OpenXML_Rels_CommitNewChartRids, when the merged chart ids are replaced by the proper xml tags, the files are created in word/charts and de references updated. The ContentTypes gets updated there too.
Hope it helps!
|