Skip to content

Commit

Permalink
steps gui pane
Browse files Browse the repository at this point in the history
  • Loading branch information
e3rd committed Oct 26, 2023
1 parent 0e55a4d commit b3f6ec5
Show file tree
Hide file tree
Showing 12 changed files with 500 additions and 194 deletions.
151 changes: 88 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ What can you acheive? See a variety of features in another example at [examples/
* [Organizing](#organizing)
- [Structure](#structure)
* [Frame `<article>`](#frame-article)
- [`data-duration`](#data-duration)
- [`data-transition-duration`](#data-transition-duration)
- [`data-spread-frames`](#data-spread-frames)
- [`data-x`, `data-y`](#data-x-data-y)
- [`data-loop`](#data-loop)
- [`id`](#id)
- [`<!-- presenter's notes -->`](#---presenters-notes---)
* [Frame content](#frame-content)
- [`data-step`](#data-step)
* [Step styling](#step-styling)
- [`data-step-class`](#data-step-class)
- [`data-step-shown`](#data-step-shown)
- [`data-step-li`](#data-step-li)
- [`data-step-duration`](#data-step-duration)
- [`data-step-transition-duration`](#data-step-transition-duration)
Expand All @@ -54,6 +62,8 @@ What can you acheive? See a variety of features in another example at [examples/
- [Panoramatic images](#panoramatic-images)
- [Preload](#preload)
+ [`<video>`](#video)
- [`data-playback-rate`](#data-playback-rate)
- [`data-video`](#data-video)
+ [Text](#text)
* [Map](#map)
+ [`<article-map>` frame](#article-map-frame)
Expand Down Expand Up @@ -129,53 +139,64 @@ Every frame is represented by an `<article>` tag.

Which contains arbitrary HTML code, such as images or videos (by default, one per slide). Use control attributes:

* `data-duration=0`: How many seconds will a frame step last. By default, indefinitely (waiting for a user action).
### `data-duration`
(default `0`) How many seconds will a frame step last. By default, indefinitely (waiting for a user action).

```html
<article data-duration="0.5">Short frame</article>
<article>You have to click to get further</article>
<article data-duration="0.5">Short frame</article>
```
Note a video frame is an exception: will hold till the video finishes and then change frame.

* `data-transition-duration=0`: How many seconds will it take to change a frame.
* `data-spread-frames=spiral`: A viewport stands for a chessboard field. This is how the frame are positioned in the chessboard.
* `true=spiral`
* `diagonal`
* `data-x`, `data-y`: Valid only for `data-spread-frames=dialogal`. Overrides the default position. Attention, do not let the frames share the same position.
* `data-loop`: If present, images in the body will rapidly loop, creating a funny animation. (Currenly allowed only `true` value for an infitite loop.)
```html
<article data-loop>
<img src="pic1.jpg" />
<img src="pic2.jpg" />
</article>
```
* `id`: Standard HTML ID serves for navigation.
```html
<article>
<a href="#my_frame">go to a specific frame</a>
<a href="#my_section">go to the first frame in a specific section</a>
<a href="#2">go to the second frame (number may change if you add frames later)</a>
</article>
<section id=my_section>
<article>...</article>
<article id=my_frame>...</article>
</section>
```
* `<!-- presenter's notes -->` You may use HTML comments just before the frame or as the first frame child. These will be displayed in the auxiliary window while presenting.
Before the frame:
```html
<!-- I should talk about cats. -->
<article><img src='cat.jpg' /></article>
```
```html
<article data-duration="0.5">Short frame</article>
<article>You have to click to get further</article>
<article data-duration="0.5">Short frame</article>
```
Note a video frame is an exception: will hold till the video finishes and then change frame.

Inside the frame:
```html
<article>
<!-- I should talk about cats. -->
<img src='cat.jpg' />
</article>
```
### `data-transition-duration`
(default `0`) How many seconds will it take to change a frame.

### `data-spread-frames`
(default `spiral`) A viewport stands for a chessboard field. This is how the frame are positioned in the chessboard.
* `true=spiral`
* `diagonal`
### `data-x`, `data-y`
Valid only for `data-spread-frames=dialogal`. Overrides the default position. Attention, do not let the frames share the same position.

### `data-loop`
If present, images in the body will rapidly loop, creating a funny animation. (Currenly allowed only `true` value for an infitite loop.)
```html
<article data-loop>
<img src="pic1.jpg" />
<img src="pic2.jpg" />
</article>
```

### `id`
Standard HTML ID serves for navigation.
```html
<article>
<a href="#my_frame">go to a specific frame</a>
<a href="#my_section">go to the first frame in a specific section</a>
<a href="#2">go to the second frame (number may change if you add frames later)</a>
</article>
<section id=my_section>
<article>...</article>
<article id=my_frame>...</article>
</section>
```
### `<!-- presenter's notes -->`
You may use HTML comments just before the frame or as the first frame child. Markdown syntax is supported. These will be displayed in the auxiliary window while presenting.

Before the frame:
```html
<!-- I should talk about cats. -->
<article><img src='cat.jpg' /></article>
```

Inside the frame:
```html
<article>
<!-- I should talk about cats. -->
<img src='cat.jpg' />
</article>
```

## Frame content

Expand Down Expand Up @@ -351,7 +372,9 @@ When having thousands of images, your browser may choke. Use `data-src` instead
* The `<video>` tag benefits from standard attributes like `loop`, `muted`, `autoplay` and `controls` (so that controls are visible). In Chromium based browsers, only `muted` video respects `autoplay` so we recommend using `controls` too so that you may start the video with the <kbd>Space</kbd>.
* When a new frame appears, first video gets focus. Whether `autoplay` is present, it starts playing. Keys like <kbd>Space</kbd>, <kbd>Left</kbd>, <kbd>Right</kbd> stop working for frame switching to avoid interfering with the video controls.

* `data-playback-rate`: The speed of the video.
#### `data-playback-rate`
The speed of the video.

Tip: Can be adjusted by <kbd>Numpad +/-</kbd> while presenting.
```html
<article> <!-- fast video -->
Expand All @@ -362,23 +385,25 @@ Tip: Can be adjusted by <kbd>Numpad +/-</kbd> while presenting.
</article>
```

* `data-video='autoplay controls'`: All `<video>` tags inherits its value as attributes (`autoplay controls muted loop`). Tip: toggle muted by <kbd>Alt+M</kbd> while presenting.
```html
<article data-video="autoplay muted">
<video> <!-- becomes <video autoplay muted> -->
<source src="my_video.mp4#t=8,10" type="video/mp4">
</video>
</article>
<article>
<video src="my_video.mp4"> <!-- becomes <video autoplay controls> because that is the default --></video>
</article>
<article>
<video data-video='muted' src="my_video.mp4"> <!-- becomes <video muted> --></video>
</article>
<article>
<video muted src="my_video.mp4"> <!-- becomes <video autoplay controls muted> --></video>
</article>
```
#### `data-video`
(default `'autoplay controls'`) All `<video>` tags inherits its value as attributes (`autoplay controls muted loop`). Tip: toggle muted by <kbd>Alt+M</kbd> while presenting.

```html
<article data-video="autoplay muted">
<video> <!-- becomes <video autoplay muted> -->
<source src="my_video.mp4#t=8,10" type="video/mp4">
</video>
</article>
<article>
<video src="my_video.mp4"> <!-- becomes <video autoplay controls> because that is the default --></video>
</article>
<article>
<video data-video='muted' src="my_video.mp4"> <!-- becomes <video muted> --></video>
</article>
<article>
<video muted src="my_video.mp4"> <!-- becomes <video autoplay controls muted> --></video>
</article>
```

### Text

Expand Down
2 changes: 1 addition & 1 deletion slidershow/aux_window.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class AuxWindow {
switch (e.action) {
case "info":
this.$current_frame.html(e.frame)
this.$notes.html((e.notes || "").replace("\n", "<br>")).toggle(Boolean(this.$notes.html())) // hide notes if empty
this.$notes.html((e.notes || "")).toggle(Boolean(this.$notes.html())) // hide notes if empty
this.$next_frame.html(e.next_frame || "END")
case "update-step":
// Highlight the element to be revealed in the next step
Expand Down
49 changes: 43 additions & 6 deletions slidershow/change_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,47 @@ class ChangeController {
*/
constructor(playback) {
this.playback = playback
/** @type {boolean} Use to check whereas the undo operation is running.
* While performing the undo operation, it is not possible to register a new one.
* This is to prevent a common situation when restoring the state will attempt
* to re-register the undo operation.
* */
this.performing = false
/**
* @type {Array<Array>}
*/
this.changes = []

this.$button = $("<button/>", { "text": "undo", })
.on("click", () => {
this.undo()
return false
})
.prop("disabled", !this.changes.length)
}


/**
*
* @param {Function} undo
* @param {*} identity Prevent registering two successive events with the same identity check in a row.
* @param {*} extra Any parameter given to the undo callback. TODO not used
* @returns
*/
change(undo) {
this._change(this.CALLBACK, undo)
change(undo, identity = null, extra = null) {
if (identity && this.changes.length && this.changes.slice(-1)[0][2] === identity) {

console.log("43: identity", identity) // TODO

return
}

console.log("48: identity", identity) // TODO

if (this.performing) { // already doing an undo operation
return
}
this._change(this.CALLBACK, undo, identity, extra)
}

deleteItem($el) {
Expand All @@ -31,9 +60,10 @@ class ChangeController {
}


_change(name, instructions) {
this.changes.push([name, instructions])
_change(name, instructions, identity = null, extra = null) {
this.changes.push([name, instructions, identity, extra])

this.$button.prop("disabled", false)
$(window).on('beforeunload', () => true)
}

Expand All @@ -45,7 +75,7 @@ class ChangeController {
if (!this.changes.length) {
return
}
const [name, instructions] = this.changes.pop()
const [name, instructions, _, extra] = this.changes.pop()
switch (name) {
case this.DELETE_EL:
const [originalIndex, $deletedItem, xpath] = instructions
Expand All @@ -60,15 +90,22 @@ class ChangeController {
)
break;
case this.CALLBACK: // Undo the operation with a non serialized callback
instructions()
this.performing = true
instructions(extra)
this.performing = false
break;
default:
this.playback.hud.alert(`Could not undo ${name}`)
break;
}

if (!this.changes.length) {
this.$button.prop("disabled", true)
this.unblock_unload()
}
}

get_button() {
return this.$button
}
}
48 changes: 28 additions & 20 deletions slidershow/frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,16 +723,33 @@ class Frame {
if ($el.data("wzoom")) {
return $el.data("wzoom") // already initialized
}
const maxScale_default = 3
const maxScale_default = 5
let last_scale = null
const wzoom = WZoom.create($el.get()[0], {
maxScale: maxScale_default,
minScale: 1,
speed: 1,
speed: 1.5,
// We can wheel in for ever but keeping maxScale on leash.
// Because the click takes us to the current bed (and second click zooms out).
rescale: wzoom =>
wzoom.content.maxScale = Math.max(maxScale_default, wzoom.content.currentScale + 3)
rescale: wzoom => { // the function seems to be called unintuitively with grab moving
const scale = wzoom.content.currentScale
wzoom.content.maxScale = Math.max(maxScale_default, scale + 3)
$el.trigger("wzoomed", [wzoom, last_scale===scale])
last_scale = scale
},
dragScrollableOptions: {
onDrop: (_, wzoom) => $el.trigger("wzoomed", wzoom)
}
})
// Why correcting viewport? When having data-step-points and calling `zoom_set` from `prepare`,
// the frame is not at the viewport yet, thus the values are wrong. Such image seem to work
// but whenever manually zoomed, it vanishes out of the screen.
// Besides, we should center the image to a parent. However, we do not want to wrap it,
// this simulates the parent.
wzoom.viewport.originalLeft = $el.position().left
wzoom.viewport.originalTop = $el.position().top
wzoom.viewport.originalWidth = $el.width()
wzoom.viewport.originalHeight = $el.height()

$el
// we have zoomed in, do not playback further
Expand Down Expand Up @@ -772,22 +789,12 @@ class Frame {
*/
zoom_set($el, left = 0, top = 0, scale = 1, transition_duration = null, duration = null) {
const wzoom = this.zoom_init($el)

transition_duration ??= prop("step-transition-duration", $el, null, "transition-duration")

const c = wzoom.content
if (!c) {
return console.warn("Zoomed img does not exist", $el, wzoom)

}
c.currentLeft = left
c.currentTop = top
c.currentScale = scale
const orig = wzoom.options.smoothExtinction
wzoom.options.smoothExtinction = transition_duration
wzoom._transform()
wzoom.options.smoothExtinction = orig
this.add_effect(resolve => $(c.$element).on("transitionend", () => resolve()))
const orig = wzoom.options.smoothTime
wzoom.options.smoothTime = transition_duration
wzoom.transform(top, left, scale)
wzoom.options.smoothTime = orig
this.add_effect(resolve => $el.on("transitionend", () => resolve()))
return duration ?? prop("step-duration", $el, null, "duration")
}

Expand Down Expand Up @@ -816,7 +823,8 @@ class Frame {
*/
get_notes() {
const frame_dom = this.$frame.get()[0]
return find_comment(frame_dom.previousSibling, "previousSibling") || find_comment(frame_dom.firstChild, "nextSibling")
const txt = find_comment(frame_dom.previousSibling, "previousSibling") || find_comment(frame_dom.firstChild, "nextSibling")
return this.playback.menu.markdown.makeHtml(txt)

/**
*
Expand Down
Loading

0 comments on commit b3f6ec5

Please sign in to comment.