diff --git a/examples/carousel-svg/README.md b/examples/carousel-svg/README.md new file mode 100644 index 0000000..a5ca07b --- /dev/null +++ b/examples/carousel-svg/README.md @@ -0,0 +1,19 @@ +This carousel example uses `style transform` and `transition` to rotate a group of SVG triangles. + +Also, the color of each triangle changes when you hover or click/tap it. + +I built the build.js using npm and browserify. + +In my local copy of the snabbdom project root I did these preparations: +``` +npm install --save-dev babelify +npm install --save-dev babel-preset-es2015 +echo '{ "presets": ["es2015"] }' > .babelrc +``` + +I then built like this: +``` +browserify examples/carousel-svg/script.js -t babelify -o examples/carousel-svg/build.js +``` + +-- *jk* diff --git a/examples/carousel-svg/build.js b/examples/carousel-svg/build.js new file mode 100644 index 0000000..3b1d598 --- /dev/null +++ b/examples/carousel-svg/build.js @@ -0,0 +1,566 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 ? hashIdx : sel.length; + var dot = dotIdx > 0 ? dotIdx : sel.length; + var tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel; + elm = vnode.elm = isDef(data) && isDef(i = data.ns) ? document.createElementNS(i, tag) : document.createElement(tag); + if (hash < dot) elm.id = sel.slice(hash + 1, dot); + if (dotIdx > 0) elm.className = sel.slice(dot + 1).replace(/\./g, ' '); + if (is.array(children)) { + for (i = 0; i < children.length; ++i) { + elm.appendChild(createElm(children[i], insertedVnodeQueue)); + } + } else if (is.primitive(vnode.text)) { + elm.appendChild(document.createTextNode(vnode.text)); + } + for (i = 0; i < cbs.create.length; ++i) { + cbs.create[i](emptyNode, vnode); + }i = vnode.data.hook; // Reuse variable + if (isDef(i)) { + if (i.create) i.create(emptyNode, vnode); + if (i.insert) insertedVnodeQueue.push(vnode); + } + } else { + elm = vnode.elm = document.createTextNode(vnode.text); + } + return vnode.elm; + } + + function addVnodes(parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) { + for (; startIdx <= endIdx; ++startIdx) { + parentElm.insertBefore(createElm(vnodes[startIdx], insertedVnodeQueue), before); + } + } + + function invokeDestroyHook(vnode) { + var i = vnode.data, + j; + if (isDef(i)) { + if (isDef(i = i.hook) && isDef(i = i.destroy)) i(vnode); + for (i = 0; i < cbs.destroy.length; ++i) { + cbs.destroy[i](vnode); + }if (isDef(i = vnode.children)) { + for (j = 0; j < vnode.children.length; ++j) { + invokeDestroyHook(vnode.children[j]); + } + } + } + } + + function removeVnodes(parentElm, vnodes, startIdx, endIdx) { + for (; startIdx <= endIdx; ++startIdx) { + var i, + listeners, + rm, + ch = vnodes[startIdx]; + if (isDef(ch)) { + if (isDef(ch.sel)) { + invokeDestroyHook(ch); + listeners = cbs.remove.length + 1; + rm = createRmCb(ch.elm, listeners); + for (i = 0; i < cbs.remove.length; ++i) { + cbs.remove[i](ch, rm); + }if (isDef(i = ch.data) && isDef(i = i.hook) && isDef(i = i.remove)) { + i(ch, rm); + } else { + rm(); + } + } else { + // Text node + parentElm.removeChild(ch.elm); + } + } + } + } + + function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) { + var oldStartIdx = 0, + newStartIdx = 0; + var oldEndIdx = oldCh.length - 1; + var oldStartVnode = oldCh[0]; + var oldEndVnode = oldCh[oldEndIdx]; + var newEndIdx = newCh.length - 1; + var newStartVnode = newCh[0]; + var newEndVnode = newCh[newEndIdx]; + var oldKeyToIdx, idxInOld, elmToMove, before; + + while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { + if (isUndef(oldStartVnode)) { + oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left + } else if (isUndef(oldEndVnode)) { + oldEndVnode = oldCh[--oldEndIdx]; + } else if (sameVnode(oldStartVnode, newStartVnode)) { + patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue); + oldStartVnode = oldCh[++oldStartIdx]; + newStartVnode = newCh[++newStartIdx]; + } else if (sameVnode(oldEndVnode, newEndVnode)) { + patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue); + oldEndVnode = oldCh[--oldEndIdx]; + newEndVnode = newCh[--newEndIdx]; + } else if (sameVnode(oldStartVnode, newEndVnode)) { + // Vnode moved right + patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue); + parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling); + oldStartVnode = oldCh[++oldStartIdx]; + newEndVnode = newCh[--newEndIdx]; + } else if (sameVnode(oldEndVnode, newStartVnode)) { + // Vnode moved left + patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue); + parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm); + oldEndVnode = oldCh[--oldEndIdx]; + newStartVnode = newCh[++newStartIdx]; + } else { + if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); + idxInOld = oldKeyToIdx[newStartVnode.key]; + if (isUndef(idxInOld)) { + // New element + parentElm.insertBefore(createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm); + newStartVnode = newCh[++newStartIdx]; + } else { + elmToMove = oldCh[idxInOld]; + patchVnode(elmToMove, newStartVnode, insertedVnodeQueue); + oldCh[idxInOld] = undefined; + parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm); + newStartVnode = newCh[++newStartIdx]; + } + } + } + if (oldStartIdx > oldEndIdx) { + before = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm; + addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue); + } else if (newStartIdx > newEndIdx) { + removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx); + } + } + + function patchVnode(oldVnode, vnode, insertedVnodeQueue) { + var i, hook; + if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) { + i(oldVnode, vnode); + } + if (isDef(i = oldVnode.data) && isDef(i = i.vnode)) oldVnode = i; + if (isDef(i = vnode.data) && isDef(i = i.vnode)) vnode = i; + var elm = vnode.elm = oldVnode.elm, + oldCh = oldVnode.children, + ch = vnode.children; + if (oldVnode === vnode) return; + if (isDef(vnode.data)) { + for (i = 0; i < cbs.update.length; ++i) { + cbs.update[i](oldVnode, vnode); + }i = vnode.data.hook; + if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode); + } + if (isUndef(vnode.text)) { + if (isDef(oldCh) && isDef(ch)) { + if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue); + } else if (isDef(ch)) { + addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); + } else if (isDef(oldCh)) { + removeVnodes(elm, oldCh, 0, oldCh.length - 1); + } + } else if (oldVnode.text !== vnode.text) { + elm.textContent = vnode.text; + } + if (isDef(hook) && isDef(i = hook.postpatch)) { + i(oldVnode, vnode); + } + } + + return function (oldVnode, vnode) { + var i; + var insertedVnodeQueue = []; + for (i = 0; i < cbs.pre.length; ++i) { + cbs.pre[i](); + }if (oldVnode instanceof Element) { + if (oldVnode.parentElement !== null) { + createElm(vnode, insertedVnodeQueue); + oldVnode.parentElement.replaceChild(vnode.elm, oldVnode); + } else { + oldVnode = emptyNodeAt(oldVnode); + patchVnode(oldVnode, vnode, insertedVnodeQueue); + } + } else { + patchVnode(oldVnode, vnode, insertedVnodeQueue); + } + for (i = 0; i < insertedVnodeQueue.length; ++i) { + insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]); + } + for (i = 0; i < cbs.post.length; ++i) { + cbs.post[i](); + }return vnode; + }; +} + +module.exports = { init: init }; + +},{"./is":2,"./vnode":7}],7:[function(require,module,exports){ +"use strict"; + +module.exports = function (sel, data, children, text, elm) { + var key = data === undefined ? undefined : data.key; + return { sel: sel, data: data, children: children, + text: text, elm: elm, key: key }; +}; + +},{}],8:[function(require,module,exports){ +'use strict'; + +var snabbdom = require('../../snabbdom.js'); +var patch = snabbdom.init([require('../../modules/attributes'), require('../../modules/style'), require('../../modules/eventlisteners')]); +var h = require('../../h.js'); + +var vnode; + +var data = { + degRotation: 0 +}; + +function gRotation() { + //console.log("gRotation: %s", data.degRotation); + return "rotate(" + data.degRotation + "deg)"; +} + +function triangleClick(id) { + console.log("triangleClick: %s", id); + render(); +} + +function handleRotate(degs) { + data.degRotation += degs; + console.log("handleRotate: %s, %s", degs, data.degRotation); + render(); +} + +function handleReset(degs) { + data.degRotation = degs; + console.log("handleReset: %s", degs); + render(); +} + +function render() { + vnode = patch(vnode, view(data)); +} + +var hTriangle = function hTriangle(id, degRotation) { + return h("polygon#" + id, { + attrs: { + points: "-50,-88 0,-175 50,-88", + transform: "rotate(" + degRotation + ")", + "stroke-width": 3 + }, + on: { click: [triangleClick, id] } + }); +}; + +var view = function view(data) { + return h("div.view", [h("h1", "Snabbdom SVG Carousel"), h("svg", { attrs: { width: 380, height: 380, viewBox: [-190, -190, 380, 380] } }, [h("g#carousel", { style: { "-webkit-transform": gRotation(), transform: gRotation() } }, [hTriangle("yellow", 0), hTriangle("green", 60), hTriangle("magenta", 120), hTriangle("red", 180), hTriangle("cyan", 240), hTriangle("blue", 300)])]), h("button", { on: { click: [handleRotate, 60] } }, "Rotate Clockwise"), h("button", { on: { click: [handleRotate, -60] } }, "Rotate Anticlockwise"), h("button", { on: { click: [handleReset, 0] } }, "Reset")]); +}; + +window.addEventListener("DOMContentLoaded", function () { + var container = document.getElementById("container"); + vnode = patch(container, view(data)); + render(); +}); + +},{"../../h.js":1,"../../modules/attributes":3,"../../modules/eventlisteners":4,"../../modules/style":5,"../../snabbdom.js":6}]},{},[8]); diff --git a/examples/carousel-svg/index.html b/examples/carousel-svg/index.html new file mode 100644 index 0000000..3b81d87 --- /dev/null +++ b/examples/carousel-svg/index.html @@ -0,0 +1,74 @@ + + + + + + Carousel + + + + +
+ + diff --git a/examples/carousel-svg/script.js b/examples/carousel-svg/script.js new file mode 100644 index 0000000..d5b7106 --- /dev/null +++ b/examples/carousel-svg/script.js @@ -0,0 +1,74 @@ +var snabbdom = require('../../snabbdom.js'); +var patch = snabbdom.init([ + require('../../modules/attributes'), + require('../../modules/style'), + require('../../modules/eventlisteners') +]); +var h = require('../../h.js'); + +var vnode; + +var data = { + degRotation: 0 +}; + +function gRotation() { + //console.log("gRotation: %s", data.degRotation); + return "rotate(" + data.degRotation + "deg)"; +} + +function triangleClick(id) { + console.log("triangleClick: %s", id); + render(); +} + +function handleRotate(degs) { + data.degRotation += degs; + console.log("handleRotate: %s, %s", degs, data.degRotation); + render(); +} + +function handleReset(degs) { + data.degRotation = degs; + console.log("handleReset: %s", degs); + render(); +} + +function render() { + vnode = patch(vnode, view(data)); +} + +const hTriangle = (id, degRotation) => + h("polygon#" + id, { + attrs: { + points: "-50,-88 0,-175 50,-88", + transform: "rotate(" + degRotation + ")", + "stroke-width": 3 + }, + on: {click: [triangleClick, id]} + }); + +const view = (data) => + h("div.view", [ + h("h1", "Snabbdom SVG Carousel"), + h("svg", {attrs: {width: 380, height: 380, viewBox: [-190, -190, 380, 380]}}, [ + h("g#carousel", + {style: {"-webkit-transform": gRotation(), transform: gRotation()}}, [ + hTriangle("yellow", 0), + hTriangle("green", 60), + hTriangle("magenta", 120), + hTriangle("red", 180), + hTriangle("cyan", 240), + hTriangle("blue", 300) + ]) + ]), + h("button", {on: {click: [handleRotate, 60]}}, "Rotate Clockwise"), + h("button", {on: {click: [handleRotate, -60]}}, "Rotate Anticlockwise"), + h("button", {on: {click: [handleReset, 0]}}, "Reset") + ]); + +window.addEventListener("DOMContentLoaded", () => { + var container = document.getElementById("container"); + vnode = patch(container, view(data)); + render(); +});