JSFiddle - React, Tailwind, and code Playground

by sukobuto

HTML

<script src="http://sukobuto.com/cdn/knockout-es5.min.js"></script>
<h1>SVG with Knockout-ES5</h1>
<a href="http://vuejs.org/examples/svg.html">Vue.js SVG Example</a> を Knockout-ES5 に移植しました。

<div id="demo">
    
    <svg width="200" height="200">
        <polygon data-bind="attr: { points: points }"></polygon>
        <circle cx="100" cy="100" r="80"></circle>
        <!--ko foreach: stats-->
        <text data-bind="attr: { x: labelPoint.x, y: labelPoint.y }, text: label"></text>
        <!--/ko-->
    </svg>

	<div data-bind="foreach: stats">
        <div>
            <label data-bind="text: label"></label>
            <input type="range" data-bind="value: value" min="0" max="100" />
            <span data-bind="text: value"></span>
            <button data-bind="click: $parent.remove">X</button>
        </div>
	</div>
    <button data-bind="click: reverse">REVERSE</button><br/>
    <input type="text" data-bind="value: statInput"/>
    <button data-bind="click: createStat">Create a Stat</button>

</div>

CSS

body {
	font-family: Helvetica Neue, Arial, sans-serif;
}

polygon {
	fill: #42b983;
	opacity: .75;
}

circle {
	fill: transparent;
	stroke: #999;
}

text {
	font-family: Helvetica Neue, Arial, sans-serif;
	font-size: 10px;
	fill: #666;
}

label {
	display: inline-block;
	margin-left: 10px;
	width: 20px;
}

JavaScript

function AppViewModel() {
	var self = this
      , statsObs
    ;
    
	self.stats = [];
    self.statInput = "";
    ko.track(self);
    
    statsObs = ko.getObservable(self, 'stats');

	ko.defineProperty(self, 'points', function() {
		return self.stats.map(function (stat) {
			var point = stat.point;
			return point.x + ',' + point.y;
		}).join(' ');
	});
    
    self.addStat = function(data) {
        self.stats.push(new StatViewModel(data.label, data.value, statsObs));
    }
    
    self.createStat = function() {
        self.stats.push(new StatViewModel(self.statInput, 100, statsObs));
    }
    
    self.reverse = function() {
        self.stats.reverse();
    }
    
    self.remove = function(stat) {
        self.stats.remove(stat);
    }
}

function StatViewModel(label, value, list) {
	var self = this;

	self.label = label;
	self.value = value;
	ko.track(self);
    
    function valueToPoint (value, index, total) {
        var x     = 0,
            y     = -value * 0.8,
            angle = Math.PI * 2 / total * index,
            cos   = Math.cos(angle),
            sin   = Math.sin(angle),
            tx    = x * cos - y * sin + 100,
            ty    = x * sin + y * cos + 100
        return {
            x: tx,
            y: ty
        }
    }

	ko.defineProperty(self, 'point', function() {
        return valueToPoint(self.value, list().indexOf(self), list().length);
	});
    ko.defineProperty(self, 'labelPoint', function() {
        var point = valueToPoint(+self.value + 10, list().indexOf(self), list().length);
        point.x -= 4;
        point.y += 4;
        return point;
    });
}

App = new AppViewModel();
ko.applyBindings(window.App);

[
    { label: 'A', value: 100 },
    { label: 'B', value: 100 },
    { label: 'C', value: 100 },
    { label: 'D', value: 100 },
    { label: 'E', value: 100 },
    { label: 'F', value: 100 }
].forEach(App.addStat);