>

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;
  -ms-user-select: none;
  -moz-user-select: none;
  -webkit-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'));