Skip to content

Instantly share code, notes, and snippets.

@mcintyre321
Last active August 29, 2015 14:20
Show Gist options
  • Save mcintyre321/d9a12a991b280461d915 to your computer and use it in GitHub Desktop.
Save mcintyre321/d9a12a991b280461d915 to your computer and use it in GitHub Desktop.
Konva + Tween
(function() {
var __hasProp = {}.hasOwnProperty;
(function(factory) {
if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
return factory(require('knockout'), exports);
} else if (typeof define === 'function' && define['amd']) {
return define(['knockout', 'exports'], factory);
} else {
return factory(ko, ko.konva = {});
}
})(function(ko, exports) {
var applyAnimations, applyEvents, applyInteractivityEventsCallback, ctor, expandConfig, getKonvaContainerIndex, makeBindingHandler, nodeFactory, nodeType, redraw, register;
expandConfig = function(config) {
var key, realValue, result, value, _ref;
result = {};
_ref = ko.utils.unwrapObservable(config);
for (key in _ref) {
value = _ref[key];
realValue = ko.utils.unwrapObservable(value);
if (typeof realValue !== 'undefined') {
result[key] = realValue;
}
}
return result;
};
applyAnimations = function(node, animations) {
var key, value, _fn;
_fn = function(key, value) {
var fn, trans;
trans = null;
if (typeof node[key] === 'function') {
fn = function(value) {
var error;
try {
return node[key](value);
} catch (_error) {
error = _error;
}
};
if (ko.isSubscribable(value)) {
return value.subscribe(function(newValue) {
if (trans) {
trans.stop();
}
if (newValue) {
return trans = fn(newValue);
}
});
} else {
if (value != null) {
return fn(value);
}
}
}
};
for (key in animations) {
if (!__hasProp.call(animations, key)) continue;
value = animations[key];
_fn(key, value);
}
};
applyEvents = function(node, element, events) {
var baseName, key, listener, listeners, name, removeEvents, value, _fn, _i, _j, _len, _len1, _ref;
removeEvents = [];
_ref = node.eventListeners;
for (baseName in _ref) {
if (!__hasProp.call(_ref, baseName)) continue;
listeners = _ref[baseName];
for (_i = 0, _len = listeners.length; _i < _len; _i++) {
listener = listeners[_i];
if (listener.name === 'knockout') {
removeEvents.push(baseName);
}
}
}
for (_j = 0, _len1 = removeEvents.length; _j < _len1; _j++) {
name = removeEvents[_j];
node.off("" + name + ".knockout");
}
_fn = function(key, value) {
return node.on("" + key + ".knockout", function(evt) {
return value(element, evt);
});
};
for (key in events) {
if (!__hasProp.call(events, key)) continue;
value = events[key];
_fn(key, value);
}
};
redraw = function(node) {
var drawTarget, layer;
if (node.getStage()) {
drawTarget = (function() {
var _i, _len, _ref;
if (node.nodeType === 'Stage') {
_ref = node.children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
layer = _ref[_i];
clearTimeout(layer._kktimeout);
}
return node;
} else {
return node.getLayer();
}
})();
drawTarget = typeof node.draw === 'function' ? node : node.getLayer();
clearTimeout(drawTarget._kktimeout);
return drawTarget._kktimeout = setTimeout((function(drawTarget) {
return function() {
return drawTarget.draw();
};
})(drawTarget), 1);
}
};
getKonvaContainerIndex = function(ancestor, element, state) {
var child, isKonvaBinding, result;
if (state == null) {
state = {
index: 0
};
}
isKonvaBinding = function(e) {
return e._kk != null;
};
child = ko.virtualElements.firstChild(ancestor);
while (child != null) {
if (child._kk === element._kk) {
return state.index;
}
if (isKonvaBinding(child)) {
state.index += 1;
} else {
result = getKonvaContainerIndex(child, element, state);
if (result >= 0) {
return result;
}
}
child = ko.virtualElements.nextSibling(child);
}
return -1;
};
applyInteractivityEventsCallback = function(node, valueAccessor) {
return node.on("pointerup mouseup dragend mouseout", function() {
var attr, attributes, values;
attributes = node.getAttrs();
values = valueAccessor();
for (attr in attributes) {
if (!attributes.hasOwnProperty(attr)) {
continue;
}
if (values.hasOwnProperty(attr)) {
values[attr](attributes[attr]);
}
}
return null;
});
};
makeBindingHandler = function(nodeFactory) {
return {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var config, index, innerContext, kk, node, params;
params = expandConfig(valueAccessor());
config = params.config || params.animate || params.events ? params.config : params;
node = nodeFactory(config, element.parentNode);
element._kk = node;
innerContext = bindingContext.createChildContext(viewModel);
ko.utils.extend(innerContext, {
'knockout-konva': {
parentElement: element,
parentNode: node
}
});
ko.applyBindingsToDescendants(innerContext, element);
applyInteractivityEventsCallback(node, valueAccessor);
kk = bindingContext['knockout-konva'] || {};
if (kk.parentNode) {
kk.parentNode.add(node);
index = getKonvaContainerIndex(kk.parentElement, element);
if (index < 0) {
throw new Error("element not contained within parent");
}
node.setZIndex(index);
}
ko.utils.domNodeDisposal.addDisposeCallback(element, (function(node) {
return function() {
var child, parent, _i, _len, _ref, _results;
parent = node.getParent();
if (!parent) {
return;
}
_ref = parent.children;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
if (!(child === node)) {
continue;
}
node.remove();
redraw(parent);
break;
}
return _results;
};
})(node));
if (element.style) {
element.style.display = 'none';
}
applyAnimations(node, params.animate);
applyEvents(node, element, params.events);
return {
controlsDescendantBindings: true
};
},
update: function(element, valueAccessor) {
var config, node, params, parent;
node = element._kk;
parent = node.getParent() || null;
params = expandConfig(valueAccessor());
config = params.config || params.events || params.animate ? params.config : params;
/* added code */
if (config.tween){
for(var p in config.tween)
config.tween[p] = config.tween[p] || config[p];
config.tween.node = node;
var tween = new Konva.Tween(config.tween);
tween.play();
}else{
node.setAttrs(config);
}
/* end of added code */
applyAnimations(node, params.animate);
applyEvents(node, element, params.events);
if (parent) {
redraw(parent);
}
return redraw(node);
}
};
};
register = function(name, factory) {
ko.bindingHandlers[name] = makeBindingHandler(factory);
return ko.virtualElements.allowedBindings[name] = true;
};
exports['register'] = register;
for (nodeType in Konva) {
ctor = Konva[nodeType];
if (!(typeof ctor === 'function')) {
continue;
}
nodeFactory = (function(nodeType, ctor) {
if (nodeType === 'Stage') {
return function(config, parent) {
var div;
div = document.createElement('div');
parent.appendChild(div);
config['container'] = div;
return new ctor(config);
};
} else {
return function(config) {
return new ctor(config);
};
}
})(nodeType, ctor);
register("Konva." + nodeType, nodeFactory);
}
});
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment