SVG Component
<div id="app"></div><div class="template"> <div class="app"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="200"> <rect transform?="translate(150, 100) rotate(@{ $.slider1.value }) scale(@{ $.slider2.value }, @{ $.slider3.value })" width="20" height="20" x-style="fill: rgb(0,255,0);"></rect> <circle cx="150" cy="100" r="2" x-style="fill: rgb(255,0,0)"></circle> <g x-type="TextSlider" transform="translate(10, 10)" name="rotate" max="360" x-ref="slider1"></g> <g x-type="TextSlider" transform="translate(10, 30)" name="scaleX" min="1.0" max="5.0" x-ref="slider2"></g> <g x-type="TextSlider" transform="translate(10, 50)" name="scaleY" min="1.0" max="5.0" x-ref="slider3"></g> </svg> </div></div><div class="template"> <g class="text-slider" xmlns="http://www.w3.org/2000/svg"> <text transform="translate(0, 10)">&{ $.name }</text> <text transform="translate(50, 10)">: @{ $.value }</text> <g x-type="Slider" x-ref="slider" transform="translate(120, 0)" max&="$.max" min&="$.min" value#="$.value"></g> </g></div><div class="template"> <g class="slider" xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="2" y="5" class="track"></rect> <circle cx@="$.normalize($.value)" cy="6" r="6" class="button" x-ref="btn" mousedown+="$.onMouseChange"></circle> </g></div>* { font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", sans-serif;}.template { display: none;}svg { background-color: #eee; user-select: none; user-select: none; user-select: none; user-select:none}.slider .track { fill: rgb(200,200,200);}.slider .button { cursor: pointer; fill: rgb(240,240,240); stroke-width: 1px; stroke: rgb(160,160,160);}var Component = Exact.Component;var Skin = Exact.Skin;function Slider() { Component.apply(this, arguments);}Exact.defineClass({ constructor: Slider, extend: Component, statics: { defaults: function() { return { min: 0, max: 10, value: 0 }; }, template: Skin.query('.template .slider') }, onMouseChange: function(event) { switch (event.type) { case 'mousemove': if (this.pressed) { var max = Number(this.max); var min = Number(this.min); //var cx = event.clientX - this.$skin.getBoundingClientRect().left; var cx = event.clientX - Skin.call(this.$skin, 'getBoundingClientRect').left; cx = cx < 0 ? 0 : cx; cx = cx > 100 ? 100 : cx; this.set('value', (cx * 0.01 * (max - min) + min).toFixed(1)); } break; case 'mousedown': this.pressed = true; break; case 'mouseup': this.pressed = false; break; } }, register: function() { Exact.help(this).bind('onMouseChange'); }, ready: function() { var body = document.body; body.addEventListener('mousemove', this.onMouseChange); body.addEventListener('mouseup', this.onMouseChange); var self = this; this.on('changed', function(event) { if (event.keyName !== 'value') { var value = self.value; value = value < self.min ? self.min : value; value = value > self.max ? self.max : value; self.set('value', value); } }); }, normalize: function(value) { return (value - this.min) / (this.max - this.min) * 100; }});function TextSlider() { Component.apply(this, arguments);}Exact.defineClass({ constructor: TextSlider, extend: Component, statics: { template: Skin.query('.template .text-slider'), resources: { Slider: Slider }, defaults: function() { return { min: 0, max: 10, value: 0, label: '' }; } }});function App() { Component.apply(this, arguments);}Exact.defineClass({ constructor: App, extend: Component, statics: { template: Skin.query('.template .app'), resources: { TextSlider: TextSlider } }});Component.create(App).attach(Skin.query('#app'));