Innerwiki: Add support for SVG overlays

allow-filter-duplicates
Jermolene 2019-01-28 18:21:24 +00:00
rodzic 049244e8a8
commit b6d901f888
4 zmienionych plików z 92 dodań i 30 usunięć

Wyświetl plik

@ -45,10 +45,28 @@ var TW_Element = function(tag,namespace) {
this.attributes = {};
this.isRaw = false;
this.children = [];
this.style = {};
this._style = {};
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
Object.defineProperty(TW_Element.prototype, "style", {
get: function() {
return this._style;
},
set: function(str) {
var self = this;
str = str || "";
$tw.utils.each(str.split(";"),function(declaration) {
var parts = declaration.split(":"),
name = $tw.utils.trim(parts[0]),
value = $tw.utils.trim(parts[1]);
if(name && value) {
self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
}
});
}
});
Object.defineProperty(TW_Element.prototype, "nodeType", {
get: function() {
return 1;
@ -169,13 +187,13 @@ Object.defineProperty(TW_Element.prototype, "outerHTML", {
}
}
}
if(this.style) {
if(this._style) {
var style = [];
for(var s in this.style) {
style.push(s + ":" + this.style[s] + ";");
for(var s in this._style) {
style.push($tw.utils.convertPropertyNameToStyleName(s) + ":" + this._style[s] + ";");
}
if(style.length > 0) {
output.push(" style=\"",style.join(""),"\"")
output.push(" style=\"",style.join(""),"\"");
}
}
output.push(">");

Wyświetl plik

@ -8,5 +8,7 @@ To try these examples under Node.js:
# Execute the following command in the root of the TiddlyWiki 5 repo:
```
./tiddlywiki.js editions/innerwikidemo --screenshot '[[$:/plugins/tiddlywiki/innerwiki/examples]]' 4
./tiddlywiki.js editions/innerwikidemo --screenshot '[[$:/plugins/tiddlywiki/innerwiki/examples]]' 4 --render '[[$:/plugins/tiddlywiki/innerwiki/examples]]' "examples.html"
```
Open `examples.html` to see the generated static HTML rendering.

Wyświetl plik

@ -1,5 +1,11 @@
title: $:/plugins/tiddlywiki/innerwiki/examples
\define big-arrow(x,y,colour:"#ff0000",border:"#000000")
<g transform="translate($x$,$y$)">
<path d="m-81.43106,34.99315l40.25737,-49.78116l40.25737,49.78116l-20.12869,0l0,50.02069l-40.25737,0l0,-50.02069l-20.12869,0l0,0z" fill="$colour$" stroke="$border$" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="5" transform="rotate(49.3775 -41.1737 35.1129)"/>
</g>
\end
\define example(text)
<$codeblock code=<<__text__>>/>
@ -12,10 +18,10 @@ $text$
The innerwiki widget specifies the dimensions of the virtual screen used to render the wiki (in pixels) and CSS styles to apply to it. Nested `<$data>` widgets are used to specify individual payload tiddlers to be loaded into the wiki. In this example, we initialise the innerwiki with two tiddlers "HelloThere" and "$:/DefaultTiddlers":
<<example """<$innerwiki width="1200" height="400" style="width:100%;" filename="screenshot-1">
<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" filename="screenshot-1.png">
<$data title="HelloThere" text="This tiddler is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
</$innerwiki>""">>
</$innerwiki>"""/>
Note that the "screenshot" is a shrunken but fully interactive TiddlyWiki.
@ -24,50 +30,70 @@ Note that the "screenshot" is a shrunken but fully interactive TiddlyWiki.
To render these examples as a PNG bitmap under Node.js, execute the following at the command prompt:
```
tiddlywiki mywiki --screenshot $:/plugins/tiddlywiki/innerwiki/examples
tiddlywiki editions/innerwikidemo --screenshot $:/plugins/tiddlywiki/innerwiki/examples
```
The screenshots will be saved as `screenshot-1.png` etc in the `./output` folder of the wiki.
To render this example tiddler as a static HTML file that embeds the screenshot images and includes the SVG overlays:
```
tiddlywiki editions/innerwikidemo --render '[[$:/plugins/tiddlywiki/innerwiki/examples]]' "examples.html" --build index
```
!! SVG overlays
Any displayable content within innerwiki widget is displayed within an automatically created SVG element. This allows overlays to be added:
<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" filename="screenshot-2.png">
<$data title="HelloThere" text="This tiddler is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
<circle cx="600" cy="50" r="40" stroke="black" stroke-width="2" fill="green" />
<<big-arrow 600 50>>
</$innerwiki>"""/>
Notice how macros can be used to encapsulate SVG fragments ([[see the source of this tiddler|$:/plugins/tiddlywiki/innerwiki/examples]]).
!! Clipping
A clipping rectangle can be applied to limit the area of the wiki that is displayed. For example:
<<example """<$innerwiki width="1200" height="400" style="width:100%;" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" filename="screenshot-2">
<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" filename="screenshot-3.png">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
</$innerwiki>""">>
</$innerwiki>"""/>
!! Transcluding payload tiddlers
This example shows how the `<$data>` widget can be transcluded from other tiddlers (see $:/plugins/tiddlywiki/innerwiki/example-data):
<<example """<$innerwiki width="600" height="400" style="width:100%;" filename="screenshot-3">
<$macrocall $name="example" text="""<$innerwiki width="600" height="400" style="width:100%;" filename="screenshot-4.png">
{{$:/plugins/tiddlywiki/innerwiki/example-data}}
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
</$innerwiki>""">>
</$innerwiki>"""/>
!! Customising the wiki state
By injecting the right payload tiddlers, the innerwiki can be initialised to any desired state. In this example we inject a configuration tiddler to make the "more" page control button visible, and a state tiddler to cause the dropdown to appear:
<<example """<$innerwiki template="$:/plugins/tiddlywiki/innerwiki/template" filename="screenshot-4" width="1200" height="400" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" style="width:100%;">
<$macrocall $name="example" text="""<$innerwiki template="$:/plugins/tiddlywiki/innerwiki/template" filename="screenshot-5.png" width="1200" height="400" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" style="width:100%;">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
<$data title="$:/config/PageControlButtons/Visibility/$:/core/ui/Buttons/more-page-actions" text="show"/>
<$data title="$:/state/popup/more--1600698846" text="(151,144,21,25)"/>
</$innerwiki>""">>
</$innerwiki>"""/>
!! Inception
An innerwiki can itself contain an inner-innerwiki:
<<example """<$innerwiki width="1200" height="600" style="width:100%;" filename="screenshot-5">
<$macrocall $name="example" text="""<$innerwiki width="1200" height="600" style="width:100%;" filename="screenshot-6.png">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere $:/plugins/tiddlywiki/innerwiki/inner-example"/>
<$data $tiddler="$:/plugins/tiddlywiki/innerwiki"/>
</$innerwiki>""">>
<<big-arrow 100 50 colour:#00ff00>>
</$innerwiki>"""/>
(You can see the innerwiki here: $:/plugins/tiddlywiki/innerwiki/inner-example)

Wyświetl plik

@ -40,11 +40,19 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
classes.push("tc-innerwiki-wrapper");
domWrapper.className = classes.join(" ");
domWrapper.style = this.innerWikiStyle;
domWrapper.style.overflow = "hidden";
domWrapper.style.position = "relative";
domWrapper.style.boxSizing = "content-box";
// Set up the SVG container
var domSVG = this.document.createElementNS("http://www.w3.org/2000/svg","svg");
domSVG.style = this.innerWikiStyle;
domSVG.style.position = "absolute";
domSVG.style.zIndex = "1";
domSVG.setAttribute("viewBox","0 0 " + this.innerWikiClipWidth + " " + this.innerWikiClipHeight);
domWrapper.appendChild(domSVG);
this.setVariable("namespace","http://www.w3.org/2000/svg");
// If we're on the real DOM, adjust the wrapper and iframe
if(!this.document.isTiddlyWikiFakeDom) {
domWrapper.style.overflow = "hidden";
domWrapper.style.position = "relative";
domWrapper.style.boxSizing = "content-box";
// Create iframe
var domIFrame = this.document.createElement("iframe");
domIFrame.className = "tc-innerwiki-iframe";
@ -54,10 +62,16 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
domIFrame.width = this.innerWikiWidth;
domIFrame.height = this.innerWikiHeight;
domWrapper.appendChild(domIFrame);
} else {
// Create image placeholder
var domImage = this.document.createElement("img");
domImage.style = this.innerWikiStyle;
domImage.setAttribute("src",this.innerWikiFilename);
domWrapper.appendChild(domImage);
}
// Insert wrapper into the DOM
parent.insertBefore(domWrapper,nextSibling);
this.renderChildren(domWrapper,null);
this.renderChildren(domSVG,null);
this.domNodes.push(domWrapper);
// If we're on the real DOM, finish the initialisation that needs us to be in the DOM
if(!this.document.isTiddlyWikiFakeDom) {
@ -65,14 +79,16 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
domIFrame.contentWindow.document.open();
domIFrame.contentWindow.document.write(this.createInnerHTML());
domIFrame.contentWindow.document.close();
// Scale the iframe and adjust the height of the wrapper
var clipLeft = self.innerWikiClipLeft,
clipTop = self.innerWikiClipTop,
clipWidth = self.innerWikiClipWidth,
clipHeight = self.innerWikiClipHeight,
translateX = -clipLeft,
translateY = -clipTop,
scale = domWrapper.clientWidth / clipWidth;
}
// Scale the iframe and adjust the height of the wrapper
var clipLeft = this.innerWikiClipLeft,
clipTop = this.innerWikiClipTop,
clipWidth = this.innerWikiClipWidth,
clipHeight = this.innerWikiClipHeight,
translateX = -clipLeft,
translateY = -clipTop,
scale = domWrapper.clientWidth / clipWidth;
if(!this.document.isTiddlyWikiFakeDom) {
domIFrame.style.transformOrigin = (-translateX) + "px " + (-translateY) + "px";
domIFrame.style.transform = "translate(" + translateX + "px," + translateY + "px) scale(" + scale + ")";
domWrapper.style.height = (clipHeight * scale) + "px";
@ -205,7 +221,7 @@ InnerWikiWidget.prototype.saveScreenshot = function(options,callback) {
return callback(null);
}
var path = require("path"),
filepath = path.resolve(basepath,this.innerWikiFilename) + ".png";
filepath = path.resolve(basepath,this.innerWikiFilename);
$tw.utils.createFileDirectories(filepath);
console.log("Taking screenshot",filepath);
// Fire up Puppeteer