getNamespace() !== NS_AV_ANNOT ) { return false; } return parent::canBeUsedOn( $title ); } public function supportsPreloadContent(): bool { return true; } public function serializeContent( Content $content, $format = null ) { return parent::serializeContent( $content, $format ); } public function unserializeContent( $text, $format = null ) { return new AnnotationContent( $text ); } public function makeEmptyContent() { return new AnnotationContent( '' ); } protected function fillParserOutput( Content $content, ContentParseParams $cpoParams, ParserOutput &$output ) { self::console_log('Fill Parser Output', true); parent::fillParserOutput( $content, $cpoParams, $output ); try { $metadata = toml_decode($content->getText(), true); } catch (TomlError $e) { $output->addWarningMsg( $e->getMessage() ); $output->setText( 'No image available' ); return; } if (isset($metadata['baseImage'])) { $imageTitle = Title::makeTitleSafe( NS_FILE, $metadata['baseImage'] ); $baseImage = MediaWikiServices::getInstance()->getRepoGroup()->findFile($imageTitle); } else { $baseImage = false; } $output->setText( self::buildSvg($metadata,$baseImage) ); } /** * Build annotated SVG from TOML metadata * * This takes in the metadata text from the file page (or the current editor) * and produces the html string for the svg with base image and annotations. * * @param string $metadata The metadata object parsed from the text * @param File $baseImage The full url pointing to the base image to annotate * @return string Html string of the complete svg */ private function buildSvg($metadata, $baseImage) { //Gather basic data $elBaseImg = ''; $vbHeight = 100; $vbWidth = 100; if ($baseImage) { $baseImageUrl = $baseImage->getFullUrl(); $baseHeight = $baseImage->getHeight(); $baseWidth = $baseImage->getWidth(); $baseAspect = $baseHeight / $baseWidth; $vbWidth = 100 / sqrt($baseAspect); $vbHeight = $baseAspect * $vbWidth; $attrBase = array( 'class' => 'annot-base', 'preserveAspectRatio' => 'none', 'width' => $vbWidth, 'height' => $vbHeight, 'href' => $baseImageUrl ); $elBaseImg = Html::rawElement('image', $attrBase); } //Render and return svg $attrSvg = array( 'class' => 'annot-svg', 'version' => '1.1', 'viewBox' => "0 0 {$vbWidth} {$vbHeight}", 'xml:space' => 'preserve', 'xmlns' => 'http://www.w3.org/2000/svg' ); if ($this->parameters['width'] > 0) { $attrSvg['width'] = $this->parameters['width']; } elseif ($this->parameters['height'] > 0) { $attrSvg['height'] = $this->parameters['height']; } if (isset($metadata['annotation'])) { $markers = []; $maskCircles = []; foreach($metadata['annotation'] as $label => $annot) { if (isset($annot['position'])) { $attrMask = array( 'cx' => $annot['position']['0'], 'cy' => $annot['position']['1'], 'r' => '3.75', 'fill' => 'black' ); $maskCirc = Html::rawElement('circle',$attrMask); array_push($maskCircles,$maskCirc); $attrMarkerCirc = array( 'cx' => $annot['position']['0'], 'cy' => $annot['position']['1'], 'r' => '3.75', 'style' => 'fill-opacity: .35; stroke-linejoin: bevel; stroke-width: .3793; stroke: #ff0000;', 'fill' => (isset($annot['light']) && $annot['light']) ? 'white' : 'balck' ); $markCirc = Html::rawElement('circle',$attrMarkerCirc); array_push($markers,$markCirc); $attrMarkerText = array( 'x' => $annot['position']['0'], 'y' => $annot['position']['1'], 'style' => 'fill: #ff0000; font-size: 5px; stroke-linejoin: bevel; stroke-width: .6968; text-align: center; text-anchor: middle; transform: translateY(1.5px);' ); $markText = Html::rawElement('text',$attrMarkerText, isset($annot['label']) ? $annot['label'] : $label ); array_push($markers,$markText); } } } return Html::rawElement('svg', $attrSvg, $elBaseImg . implode($markers) ); } public function validateSave( Content $content, ValidationParams $validationParams ) { self::console_log('Validate Save', true); $status = Status::newGood(); try { $tomlCheck = toml_decode($content->getText(), true); } catch (TomlError $e) { $status->fatal( 'content-failed-to-parse', 'SVG', "", $e->getMessage() ); } return $status; } /** * Small helper function to display information on the browser console * * Usage: * echo ''; * * @param $data information to display * @param bool $add_script_tags true to put information is inside complete script tag */ public static function console_log($data, $add_script_tags = false) { $command = 'console.log('. json_encode($data, JSON_HEX_TAG).');'; if ($add_script_tags) { $command = ''; } echo $command; } }