image
by goldfingerxyz
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<link rel="stylesheet" href="http://twitter.github.io/bootstrap/assets/css/bootstrap.css">
<div class="container">
<div class="row">
<div class="span">
<h2>Image choices</h2>
</div>
</div>
<div class="row images" >
<div class="span" data-bind="foreach: images">
<a href="#" data-bind="css: { selected: $parent.selectedImage() === $data }">
<img data-bind="click: $parent.selectedImage, attr: { src: url, title: name }" />
</a>
</div>
</div>
<div class="row">
<div class="span4">
<div class="editor" data-bind="paper: true, images: { data: images, click: selectedImage }"></div>
</div>
<div class="tools span4" data-bind="with: selectedImage">
<div class="row">
<h3>Move (<span data-bind="text: x() + ',' + y()"></span>)</h3>
</div>
<div class="row move">
<i class="icon icon-arrow-up" data-bind="click: moveUp"></i>
<i class="icon icon-arrow-left" data-bind="click: moveLeft"></i>
<i class="icon icon-arrow-right" data-bind="click: moveRight"></i>
<i class="icon icon-arrow-down" data-bind="click: moveDown"></i>
</div>
<div class="row">
<h3>Rotate (<span data-bind="text: rotation"></span>)</h3>
</div>
<div class="row rotate">
<i class="icon icon-repeat" data-bind="click: turnCounterClockwise"></i>
<i class="icon icon-undo" data-bind="click: turnClockwise"></i>
</div>
<div class="row">
<h3>Size (<span data-bind="text: scale().toFixed(1)"></span>)</h3>
</div>
<div...
CSS
@import "//netdna.bootstrapcdn.com/font-awesome/3.0/css/font-awesome.css";
.container { margin-left: 50px; }
.tools { padding-left: 20px; }
.tools .icon {
font-size: 2em;
position: absolute;
cursor: pointer;
width: 32px;
}
.move, .rotate, .size {
position: relative;
height: 30px;
}
.move { height: 60px; }
.icon-arrow-up { left: 20px; top: -15px; }
.icon-arrow-left { left: 0; top: 6px; }
.icon-arrow-right { left: 42px; top: 6px; }
.icon-arrow-down { left: 20px; top: 26px; }
.icon-minus { top: -10px; }
.icon-plus { left: 36px; top: -10px; }
.icon-undo { top: -10px; }
.icon-repeat { left: 36px; top: -10px; }
.icon:hover { color: blue; }
.editor {
background-color: #ccc;
height: 300px;
width: 300px;
}
.editor image {
cursor: pointer;
}
.images { padding-bottom: 10px; }
.images .selected img { border: solid 2px green; }
.images img {
width: 60px;
padding: 5px;
border: solid 2px #ccc;
}
.images img:hover { border: solid 2px blue; }
.links { display: none; }
JavaScript
ko.bindingHandlers.paper = {
init: function(element, valueAccessor) {
var paper = Raphael(element);
ko.utils.domData.set(element, "paper", paper);
}
};
ko.bindingHandlers.images = {
init: function(element, valueAccessor, allBindings, vm, context) {
var options = ko.utils.unwrapObservable(valueAccessor()),
images = options && ko.utils.unwrapObservable(options.data);
ko.utils.arrayForEach(images || [], function(image) {
ko.applyBindingsToNode(element, {
image: {
data: image,
click: options.click
}
}, context);
});
}
};
ko.bindingHandlers.image = {
init: function(element, valueAccessor, allBindings, vm, context) {
var paper = ko.utils.domData.get(element, "paper"),
image = paper.image("", 0, 0, 50, 50),
options = ko.utils.unwrapObservable(valueAccessor()),
data = options.data;
if (typeof options.click === "function") {
ko.applyBindingsToNode(image[0], {
click: options.click
}, context.createChildContext(ko.utils.unwrapObservable(options.data)))
}
//set up computed to separately process url
ko.computed({
read: function() {
var imageData = ko.utils.unwrapObservable(data),
url = imageData && ko.utils.unwrapObservable(imageData.url);
image.attr("src", url);
},
disposeWhenNodeIsRemove: element
});
//separate computed to process transform information
ko.computed({
read: function() {
var imageData = ko.utils.unwrapObservable(data),
rotation, scale, x, y;
if (imageData) {
rotation = ko.utils.unwrapObservable(imageData.rotation) || 0;
scale = ko.utils.unwrapObservable(imageData.scale) || 1;
x = ko.utils.unwrapObservable(imageData.x) || 0;
y =...