<commit_before>var fs = require("fs");
var path = require("path");
var userpath = path.join(require("os").homedir(), ".efront");
var userdatafile = path.join(userpath, 'profile');
var JSAM = require("../basic/JSAM");
var lazy = require("../basic/lazy");
var encode62 = require('../crypt/encode62');
var profile = {
    code: encode62.geta(Math.random().toString(36).slice(2)),
};
function save(pathname, data) {
    var fullpath = path.join(userpath, pathname);
    var folderpath = path.dirname(fullpath)
    if (!fs.existsSync(folderpath)) fs.mkdirSync(folderpath, { recursive: true });
    fs.writeFileSync(fullpath, JSAM.stringify(data));
}
function load(pathname) {
    var fullpath = path.join(userpath, pathname);
    if (!fs.existsSync(fullpath)) return;
    var data = fs.readFileSync(fullpath);
    return JSAM.parse(data);
}
var profile_promise = null;
var loadProfileAsync = function () {
    if (profile_promise || !fs.existsSync(userdatafile)) return profile_promise;
    return profile_promise = new Promise(function (ok, oh) {
        fs.readFile(userdatafile, function (error, buff) {
            if (error) return oh(error);
            ok(buff);
        });
    }).then(function (data) {
        data = String(data);
        data = JSAM.parse(data);
        Object.assign(profile, data);
    }, console.error);
};
var saveProfileAsync = lazy(async function () {
    var folderpath = path.dirname(userdatafile);
    try {
        if (!fs.existsSync(folderpath)) {
            await new Promise((ok, oh) => {
                fs.mkdir(folderpath, { recursive: true }, function (error) {
                    if (error) return oh(error);
                    ok();
                });
            });
        }
        await new Promise((ok, oh) => {
            var data = JSAM.stringify(profile);
            fs.writeFile(userdatafile, data, function (error) {
                if (error) return oh(error);
                ok();
            });
        });
    } catch (e) {
        console.error("写入文件失败！");
        return;
    }
    if (!fs.existsSync(userdatafile)) { }
}, 60);
async function setItem(k, v) {
    await loadProfileAsync();
    var k0 = encode62.geta(k + profile.code);
    profile[k0] = String(encode62.encode(v, k0));
    saveProfileAsync();
}
async function getItem(k) {
    await loadProfileAsync();
    var k0 = encode62.geta(k + profile.code);
    var v = profile[k0];
    if (!v) return;
    return String(encode62.decode(v, k0));
}

async function checkPassword(p) {
    var a = encode62.geta(p);
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    var b = encode62.da2b(d, a);
    var c0 = encode62.ab2c(a, b);
    return c0 === c;
}

async function checkPasswordA(a) {
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    var b = encode62.da2b(d, a);
    var c0 = encode62.ab2c(a, b);
    if (c0 === c) return b;
    return null;
}

async function checkPasswordB(b) {
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    var a = encode62.db2a(d, b);
    var c0 = encode62.ab2c(a, b);
    return c0 === c;
}

async function setPassword(p) {
    var a = encode62.geta(p);
    var b = encode62.genb();
    var c = encode62.ab2c(a, b);
    var d = encode62.ba2d(b, a);
    await setItem('password-c', c);
    await setItem('password-d', d);
}
async function hasPassword(p) {
    return !!await getItem("password-c");
}
module.exports = {
    save,
    load,
    setItem,
    getItem,
    hasPassword,
    setPassword,
    checkPassword,
    checkPasswordA,
    checkPasswordB,
    sign(a) {
        return encode62.ab2c(profile.code, a);
    },
    unsign(c) {
        return encode62.ca2b(c, profile.code);
    },
}<commit_msg>校检空密码时不再报错<commit_after>var fs = require("fs");
var path = require("path");
var userpath = path.join(require("os").homedir(), ".efront");
var userdatafile = path.join(userpath, 'profile');
var JSAM = require("../basic/JSAM");
var lazy = require("../basic/lazy");
var encode62 = require('../crypt/encode62');
var profile = {
    code: encode62.geta(Math.random().toString(36).slice(2)),
};
function save(pathname, data) {
    var fullpath = path.join(userpath, pathname);
    var folderpath = path.dirname(fullpath)
    if (!fs.existsSync(folderpath)) fs.mkdirSync(folderpath, { recursive: true });
    fs.writeFileSync(fullpath, JSAM.stringify(data));
}
function load(pathname) {
    var fullpath = path.join(userpath, pathname);
    if (!fs.existsSync(fullpath)) return;
    var data = fs.readFileSync(fullpath);
    return JSAM.parse(data);
}
var profile_promise = null;
var loadProfileAsync = function () {
    if (profile_promise || !fs.existsSync(userdatafile)) return profile_promise;
    return profile_promise = new Promise(function (ok, oh) {
        fs.readFile(userdatafile, function (error, buff) {
            if (error) return oh(error);
            ok(buff);
        });
    }).then(function (data) {
        data = String(data);
        data = JSAM.parse(data);
        Object.assign(profile, data);
    }, console.error);
};
var saveProfileAsync = lazy(async function () {
    var folderpath = path.dirname(userdatafile);
    try {
        if (!fs.existsSync(folderpath)) {
            await new Promise((ok, oh) => {
                fs.mkdir(folderpath, { recursive: true }, function (error) {
                    if (error) return oh(error);
                    ok();
                });
            });
        }
        await new Promise((ok, oh) => {
            var data = JSAM.stringify(profile);
            fs.writeFile(userdatafile, data, function (error) {
                if (error) return oh(error);
                ok();
            });
        });
    } catch (e) {
        console.error("写入文件失败！");
        return;
    }
    if (!fs.existsSync(userdatafile)) { }
}, 60);
async function setItem(k, v) {
    await loadProfileAsync();
    var k0 = encode62.geta(k + profile.code);
    profile[k0] = String(encode62.encode(v, k0));
    saveProfileAsync();
}
async function getItem(k) {
    await loadProfileAsync();
    var k0 = encode62.geta(k + profile.code);
    var v = profile[k0];
    if (!v) return;
    return String(encode62.decode(v, k0));
}

async function checkPassword(p) {
    var a = encode62.geta(p);
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    if (!c || !d) return false;
    var b = encode62.da2b(d, a);
    var c0 = encode62.ab2c(a, b);
    return c0 === c;
}

async function checkPasswordA(a) {
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    if (!c || !d) return null;
    var b = encode62.da2b(d, a);
    var c0 = encode62.ab2c(a, b);
    if (c0 === c) return b;
    return null;
}

async function checkPasswordB(b) {
    var c = await getItem('password-c');
    var d = await getItem('password-d');
    if (!c || !d) return null;
    var a = encode62.db2a(d, b);
    var c0 = encode62.ab2c(a, b);
    return c0 === c;
}

async function setPassword(p) {
    var a = encode62.geta(p);
    var b = encode62.genb();
    var c = encode62.ab2c(a, b);
    var d = encode62.ba2d(b, a);
    await setItem('password-c', c);
    await setItem('password-d', d);
}
async function hasPassword(p) {
    return !!await getItem("password-c");
}
module.exports = {
    save,
    load,
    setItem,
    getItem,
    hasPassword,
    setPassword,
    checkPassword,
    checkPasswordA,
    checkPasswordB,
    sign(a) {
        return encode62.ab2c(profile.code, a);
    },
    unsign(c) {
        return encode62.ca2b(c, profile.code);
    },
}<|endoftext|>


<commit_before>"use strict";

var util = require('util'),
	HTTP = require('http'),
	CONNECT = require('CONNECT'),
	DNS = require('native-dns'),
	DHCPA = require('../../lib/dhcpa')(),
	ASYNC = require('async');

module.exports = function runApplication(ELECTRON) {
	var root = 'file://' + __dirname + '/';
	var DOMAIN_SUFFIX = '.' + require('os').hostname() + '.local';

	var BrowserWindow = ELECTRON.BrowserWindow;  // Module to create native browser window.
	var Tray = ELECTRON.Tray;
	var Menu = ELECTRON.Menu;

	var DDNSServer = require('../ddns')(DNS, ASYNC);
	//var DHCPAServer = require('../dhcpa')(DHCPA, CONNECT);
	var ServiceManager = require('../servicemanager')(HTTP, CONNECT, DHCPA);
	var GossamerService = require('./service')(HTTP, CONNECT);

	this.commandLine.appendSwitch('v', -1);
	this.commandLine.appendSwitch('vmodule', 'console=0');

	// Keep a global reference of the window object, if you don't, the window will
	// be closed automatically when the javascript object is GCed.
	var mainWindow = null;
	var appTray = null, mnuTray = null;

	var quitApp = this.makeSingleInstance((cmd, cwd) => {
		!!appTray && (console.log('Forwarding: ' + cmd));
		return !!appTray
	});
	if (quitApp) {
		this.quit();
		return;
	}

	global.dnsserver = new DDNSServer();
	//global.dhcpaserver = new DHCPAServer();
	global.server = new GossamerService();
	global.serviceManager = new ServiceManager(global.dnsserver);

	// This method will be called when Electron has done everything
	// initialization and ready for creating browser windows.
	this.on('ready', () => {
		if (!!!appTray) {
			appTray = new Tray('./icons/tray.png');
			mnuTray = Menu.buildFromTemplate([
				{label: 'Item1'},
				{label: 'Item2'},
				{label: 'Item3'},
				{label: 'Quit Gossamer', click: () => {
					if (!!mainWindow) {
						mainWindow.destroy();
					}
					this.quit();
				}}
			]);
			appTray.setToolTip('Gossamer');
			appTray.setContextMenu(mnuTray);
			appTray.on('click', showMainWindow);

			global.dnsserver.start('127.255.255.254');
			global.serviceManager.address('127.99.0.1')
				.hostname('services' + DOMAIN_SUFFIX)
				.start();

			global.server.start();
		}

		var dhcpaClient = new DHCPA.Client();
		dhcpaClient.address('127.255.255.253')
			.start();

		dhcpaClient.on('listening', (address) => {
			console.log('DHCP/A Test Client listening on: ' + address);
		});
		dhcpaClient.on('message', (from, msg) => {

		});
		dhcpaClient.on('offer', (from, msg) => {
			var spkt = dhcpaClient.createRequestPacket(msg);
			//var spkt = dhcpaClient.createRequestPacket(pkt);
			dhcpaClient.send(spkt, from.port, from.address)
		});
		dhcpaClient.on('ack', (from, msg) => {

		});
		dhcpaClient.on('nak', (from, pkt) => {

		});
		//dhcpaClient.bind('127.255.255.253');

		var disc = dhcpaClient.createDiscoverPacket({
			xid: 0x01,
			chaddr: {
				address: '00:01:02:03:04:05'
			},
			options: {
				dhcpMessageType: DHCPA.Message.TYPES.DHCP_DISCOVER.value,
			}
		});
		console.log('Sending DHCP/A Discover:', util.inspect(disc, false, 3))
		dhcpaClient.broadcast(disc, undefined, () => {
			console.log('dhcpDiscover sent');
		});

	});
	this.on('will-quit', function() {
		global.dnsserver.close();
		global.server.close();
		global.serviceManager.close();
	});
	// Quit when all windows are closed.
	this.on('window-all-closed', function() { });

	function showMainWindow() {
		if (!!!mainWindow) {

		// Create the browser window.
			mainWindow = new BrowserWindow({
				width: 350,
				height: ELECTRON.screen.getPrimaryDisplay().workAreaSize.height,
				x: ELECTRON.screen.getPrimaryDisplay().workAreaSize.width - 350,
				y: 0,
				icon: './icons/tray.png',
				transparent: true,
				frame: false
			});
			mainWindow.on('close', function(event) {
				event.preventDefault();
				mainWindow.hide();
			})
		// and load the index.html of the app.
			mainWindow.loadURL(root + '../control-panel/index.html');

		// Open the devtools.
			//mainWindow.openDevTools({detach: true});
		}
		else mainWindow.show();
	}
};
<commit_msg>FIX: Use new DCHPS references<commit_after>"use strict";

var util = require('util'),
	HTTP = require('http'),
	CONNECT = require('CONNECT'),
	DNS = require('native-dns'),
//	DHCPS = require('../../lib/DHCPS')(),
	DHCPS = require('dhcps')(),
	ASYNC = require('async');

module.exports = function runApplication(ELECTRON) {
	var root = 'file://' + __dirname + '/';
	var DOMAIN_SUFFIX = '.' + require('os').hostname() + '.local';

	var BrowserWindow = ELECTRON.BrowserWindow;  // Module to create native browser window.
	var Tray = ELECTRON.Tray;
	var Menu = ELECTRON.Menu;

	var DDNSServer = require('../ddns')(DNS, ASYNC);
	var ServiceManager = require('../servicemanager')(HTTP, CONNECT, DHCPS);
	var GossamerService = require('./service')(HTTP, CONNECT);

	this.commandLine.appendSwitch('v', -1);
	this.commandLine.appendSwitch('vmodule', 'console=0');

	// Keep a global reference of the window object, if you don't, the window will
	// be closed automatically when the javascript object is GCed.
	var mainWindow = null;
	var appTray = null, mnuTray = null;

	var quitApp = this.makeSingleInstance((cmd, cwd) => {
		!!appTray && (console.log('Forwarding: ' + cmd));
		return !!appTray
	});
	if (quitApp) {
		this.quit();
		return;
	}

	global.dnsserver = new DDNSServer();
	//global.dhcpaserver = new DHCPAServer();
	global.server = new GossamerService();
	global.serviceManager = new ServiceManager(global.dnsserver);

	// This method will be called when Electron has done everything
	// initialization and ready for creating browser windows.
	this.on('ready', () => {
		if (!!!appTray) {
			appTray = new Tray('./icons/tray.png');
			mnuTray = Menu.buildFromTemplate([
				{label: 'Item1'},
				{label: 'Item2'},
				{label: 'Item3'},
				{label: 'Quit Gossamer', click: () => {
					if (!!mainWindow) {
						mainWindow.destroy();
					}
					this.quit();
				}}
			]);
			appTray.setToolTip('Gossamer');
			appTray.setContextMenu(mnuTray);
			appTray.on('click', showMainWindow);

			global.dnsserver.start('127.255.255.254');
			global.serviceManager.address('127.99.0.1')
				.hostname('services' + DOMAIN_SUFFIX)
				.start();

			global.server.start();
		}

		var dhcpaClient = new DHCPS.Client();
		dhcpaClient.address('127.255.255.253')
			.start();

		dhcpaClient.on('listening', (address) => {
			console.log('DHCP/A Test Client listening on: ' + address);
		});
		dhcpaClient.on('message', (from, msg) => {

		});
		dhcpaClient.on('offer', (from, msg) => {
			var spkt = dhcpaClient.createRequestPacket(msg);
			//var spkt = dhcpaClient.createRequestPacket(pkt);
			dhcpaClient.send(spkt, from.port, from.address)
		});
		dhcpaClient.on('ack', (from, msg) => {

		});
		dhcpaClient.on('nak', (from, pkt) => {

		});
		//dhcpaClient.bind('127.255.255.253');

		var disc = dhcpaClient.discover(1);
		console.log('Sending DHCP/A Discover:', util.inspect(disc, false, 3))
		dhcpaClient.broadcast(disc, undefined, () => {
			console.log('dhcpDiscover sent');
		});

	});
	this.on('will-quit', function() {
		global.dnsserver.close();
		global.server.close();
		global.serviceManager.close();
	});
	// Quit when all windows are closed.
	this.on('window-all-closed', function() { });

	function showMainWindow() {
		if (!!!mainWindow) {

		// Create the browser window.
			mainWindow = new BrowserWindow({
				width: 350,
				height: ELECTRON.screen.getPrimaryDisplay().workAreaSize.height,
				x: ELECTRON.screen.getPrimaryDisplay().workAreaSize.width - 350,
				y: 0,
				icon: './icons/tray.png',
				transparent: true,
				frame: false
			});
			mainWindow.on('close', function(event) {
				event.preventDefault();
				mainWindow.hide();
			})
		// and load the index.html of the app.
			mainWindow.loadURL(root + '../control-panel/index.html');

		// Open the devtools.
			//mainWindow.openDevTools({detach: true});
		}
		else mainWindow.show();
	}
};
<|endoftext|>


<commit_before>(function() {

  /* _FROM_SVG_START_ */
  function getColorStop(el) {
    var style = el.getAttribute('style'),
        offset = el.getAttribute('offset'),
        color, opacity;

    // convert percents to absolute values
    offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);

    if (style) {
      var keyValuePairs = style.split(/\s*;\s*/);

      if (keyValuePairs[keyValuePairs.length - 1] === '') {
        keyValuePairs.pop();
      }

      for (var i = keyValuePairs.length; i--; ) {

        var split = keyValuePairs[i].split(/\s*:\s*/),
            key = split[0].trim(),
            value = split[1].trim();

        if (key === 'stop-color') {
          color = value;
        }
        else if (key === 'stop-opacity') {
          opacity = value;
        }
      }
    }

    if (!color) {
      color = el.getAttribute('stop-color') || 'rgb(0,0,0)';
    }
    if (!opacity) {
      opacity = el.getAttribute('stop-opacity');
    }

    // convert rgba color to rgb color - alpha value has no affect in svg
    color = new fabric.Color(color).toRgb();

    return {
      offset: offset,
      color: color,
      opacity: isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity)
    };
  }

  function getLinearCoords(el) {
    return {
      x1: el.getAttribute('x1') || 0,
      y1: el.getAttribute('y1') || 0,
      x2: el.getAttribute('x2') || '100%',
      y2: el.getAttribute('y2') || 0
    };
  }

  function getRadialCoords(el) {
    return {
      x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',
      y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',
      r1: 0,
      x2: el.getAttribute('cx') || '50%',
      y2: el.getAttribute('cy') || '50%',
      r2: el.getAttribute('r') || '50%'
    };
  }
  /* _FROM_SVG_END_ */

  /**
   * Gradient class
   * @class fabric.Gradient
   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#gradients}
   * @see {@link fabric.Gradient#initialize} for constructor definition
   */
  fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {
    /*
     * Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
     * @type Number
     * @default 0
     */
    origX: 0,

    /*
     * Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
     * @type Number
     * @default 0
     */
    origY: 0,

    /**
     * Constructor
     * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops
     * @return {fabric.Gradient} thisArg
     */
    initialize: function(options) {
      options || (options = { });

      var coords = { };

      this.id = fabric.Object.__uid++;
      this.type = options.type || 'linear';

      coords = {
        x1: options.coords.x1 || 0,
        y1: options.coords.y1 || 0,
        x2: options.coords.x2 || 0,
        y2: options.coords.y2 || 0
      };

      if (this.type === 'radial') {
        coords.r1 = options.coords.r1 || 0;
        coords.r2 = options.coords.r2 || 0;
      }

      this.coords = coords;
      this.gradientUnits = options.gradientUnits || 'objectBoundingBox';
      this.colorStops = options.colorStops.slice();
      if (options.gradientTransform) {
        this.gradientTransform = options.gradientTransform;
      }
      this.origX = options.left;
      this.orgiY = options.top;
    },

    /**
     * Adds another colorStop
     * @param {Object} colorStop Object with offset and color
     * @return {fabric.Gradient} thisArg
     */
    addColorStop: function(colorStop) {
      for (var position in colorStop) {
        var color = new fabric.Color(colorStop[position]);
        this.colorStops.push({
          offset: position,
          color: color.toRgb(),
          opacity: color.getAlpha()
        });
      }
      return this;
    },

    /**
     * Returns object representation of a gradient
     * @return {Object}
     */
    toObject: function() {
      return {
        type: this.type,
        coords: this.coords,
        gradientUnits: this.gradientUnits,
        colorStops: this.colorStops
      };
    },

    /* _TO_SVG_START_ */
    /**
     * Returns SVG representation of an gradient
     * @param {Object} object Object to create a gradient for
     * @param {Boolean} normalize Whether coords should be normalized
     * @return {String} SVG representation of an gradient (linear/radial)
     */
    toSVG: function(object, normalize) {
      var coords = fabric.util.object.clone(this.coords),
          markup, commonAttributes;

      // colorStops must be sorted ascending
      this.colorStops.sort(function(a, b) {
        return a.offset - b.offset;
      });

      if (normalize && this.gradientUnits === 'userSpaceOnUse') {
        coords.x1 += object.width / 2;
        coords.y1 += object.height / 2;
        coords.x2 += object.width / 2;
        coords.y2 += object.height / 2;
      }
      else if (this.gradientUnits === 'objectBoundingBox') {
        _convertValuesToPercentUnits(object, coords);
      }
      commonAttributes = 'id="SVGID_' + this.id +
                     '" gradientUnits="' + this.gradientUnits + '"';
      if (this.gradientTransform) {
        commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" ';
      }
      if (this.type === 'linear') {
        markup = [
          //jscs:disable validateIndentation
          '<linearGradient ',
            commonAttributes,
            ' x1="', coords.x1,
            '" y1="', coords.y1,
            '" x2="', coords.x2,
            '" y2="', coords.y2,
          '">\n'
          //jscs:enable validateIndentation
        ];
      }
      else if (this.type === 'radial') {
        markup = [
          //jscs:disable validateIndentation
          '<radialGradient ',
            commonAttributes,
            ' cx="', coords.x2,
            '" cy="', coords.y2,
            '" r="', coords.r2,
            '" fx="', coords.x1,
            '" fy="', coords.y1,
          '">\n'
          //jscs:enable validateIndentation
        ];
      }

      for (var i = 0; i < this.colorStops.length; i++) {
        markup.push(
          //jscs:disable validateIndentation
          '<stop ',
            'offset="', (this.colorStops[i].offset * 100) + '%',
            '" style="stop-color:', this.colorStops[i].color,
            (this.colorStops[i].opacity != null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
          '"/>\n'
          //jscs:enable validateIndentation
        );
      }

      markup.push((this.type === 'linear' ? '</linearGradient>\n' : '</radialGradient>\n'));

      return markup.join('');
    },
    /* _TO_SVG_END_ */

    /**
     * Returns an instance of CanvasGradient
     * @param {CanvasRenderingContext2D} ctx Context to render on
     * @return {CanvasGradient}
     */
    toLive: function(ctx) {
      var gradient;

      if (!this.type) {
        return;
      }

      if (this.type === 'linear') {
        gradient = ctx.createLinearGradient(
          this.coords.x1, this.coords.y1, this.coords.x2, this.coords.y2);
      }
      else if (this.type === 'radial') {
        gradient = ctx.createRadialGradient(
          this.coords.x1, this.coords.y1, this.coords.r1, this.coords.x2, this.coords.y2, this.coords.r2);
      }

      for (var i = 0, len = this.colorStops.length; i < len; i++) {
        var color = this.colorStops[i].color,
            opacity = this.colorStops[i].opacity,
            offset = this.colorStops[i].offset;

        if (typeof opacity !== 'undefined') {
          color = new fabric.Color(color).setAlpha(opacity).toRgba();
        }
        gradient.addColorStop(parseFloat(offset), color);
      }

      return gradient;
    }
  });

  fabric.util.object.extend(fabric.Gradient, {

    /* _FROM_SVG_START_ */
    /**
     * Returns {@link fabric.Gradient} instance from an SVG element
     * @static
     * @memberof fabric.Gradient
     * @param {SVGGradientElement} el SVG gradient element
     * @param {fabric.Object} instance
     * @return {fabric.Gradient} Gradient instance
     * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
     * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
     */
    fromElement: function(el, instance) {

      /**
       *  @example:
       *
       *  <linearGradient id="linearGrad1">
       *    <stop offset="0%" stop-color="white"/>
       *    <stop offset="100%" stop-color="black"/>
       *  </linearGradient>
       *
       *  OR
       *
       *  <linearGradient id="linearGrad2">
       *    <stop offset="0" style="stop-color:rgb(255,255,255)"/>
       *    <stop offset="1" style="stop-color:rgb(0,0,0)"/>
       *  </linearGradient>
       *
       *  OR
       *
       *  <radialGradient id="radialGrad1">
       *    <stop offset="0%" stop-color="white" stop-opacity="1" />
       *    <stop offset="50%" stop-color="black" stop-opacity="0.5" />
       *    <stop offset="100%" stop-color="white" stop-opacity="1" />
       *  </radialGradient>
       *
       *  OR
       *
       *  <radialGradient id="radialGrad2">
       *    <stop offset="0" stop-color="rgb(255,255,255)" />
       *    <stop offset="0.5" stop-color="rgb(0,0,0)" />
       *    <stop offset="1" stop-color="rgb(255,255,255)" />
       *  </radialGradient>
       *
       */

      var colorStopEls = el.getElementsByTagName('stop'),
          type = (el.nodeName === 'linearGradient' ? 'linear' : 'radial'),
          gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',
          gradientTransform = el.getAttribute('gradientTransform'),
          colorStops = [],
          coords = { };

      if (type === 'linear') {
        coords = getLinearCoords(el);
      }
      else if (type === 'radial') {
        coords = getRadialCoords(el);
      }

      for (var i = colorStopEls.length; i--; ) {
        colorStops.push(getColorStop(colorStopEls[i]));
      }

      _convertPercentUnitsToValues(instance, coords);

      var gradient = new fabric.Gradient({
        type: type,
        coords: coords,
        gradientUnits: gradientUnits,
        colorStops: colorStops
      });

      if (gradientTransform) {
        gradient.gradientTransform = fabric.parseTransformAttribute(gradientTransform);
      }

      return gradient;
    },
    /* _FROM_SVG_END_ */

    /**
     * Returns {@link fabric.Gradient} instance from its object representation
     * @static
     * @memberof fabric.Gradient
     * @param {Object} obj
     * @param {Object} [options] Options object
     */
    forObject: function(obj, options) {
      options || (options = { });
      _convertPercentUnitsToValues(obj, options);
      return new fabric.Gradient(options);
    }
  });

  /**
   * @private
   */
  function _convertPercentUnitsToValues(object, options) {
    for (var prop in options) {
      if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
        var percents = parseFloat(options[prop], 10);
        if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
          options[prop] = fabric.util.toFixed(object.width * percents / 100, 2)  + object.left;
        }
        else if (prop === 'y1' || prop === 'y2') {
          options[prop] = fabric.util.toFixed(object.height * percents / 100, 2) + object.top;
        }
      }
    }
  }

  /* _TO_SVG_START_ */
  /**
   * @private
   */
  function _convertValuesToPercentUnits(object, options) {
    for (var prop in options) {
      //convert to percent units
      if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
        options[prop] = fabric.util.toFixed((options[prop] - object.origX) / object.width * 100, 2) + '%';
      }
      else if (prop === 'y1' || prop === 'y2') {
        options[prop] = fabric.util.toFixed((options[prop] - object.origY) / object.height * 100, 2) + '%';
      }
    }
  }
  /* _TO_SVG_END_ */

})();
<commit_msg>Update gradient.class.js<commit_after>(function() {

  /* _FROM_SVG_START_ */
  function getColorStop(el) {
    var style = el.getAttribute('style'),
        offset = el.getAttribute('offset'),
        color, colorAlpha, opacity;

    // convert percents to absolute values
    offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);

    if (style) {
      var keyValuePairs = style.split(/\s*;\s*/);

      if (keyValuePairs[keyValuePairs.length - 1] === '') {
        keyValuePairs.pop();
      }

      for (var i = keyValuePairs.length; i--; ) {

        var split = keyValuePairs[i].split(/\s*:\s*/),
            key = split[0].trim(),
            value = split[1].trim();

        if (key === 'stop-color') {
          color = value;
        }
        else if (key === 'stop-opacity') {
          opacity = value;
        }
      }
    }

    if (!color) {
      color = el.getAttribute('stop-color') || 'rgb(0,0,0)';
    }
    if (!opacity) {
      opacity = el.getAttribute('stop-opacity');
    }

    color = new fabric.Color(color);
    colorAlpha = color.getAlpha();
    color = color.toRgb();
    opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);
    opacity *= colorAlpha;

    return {
      offset: offset,
      color: color,
      opacity: opacity
    };
  }

  function getLinearCoords(el) {
    return {
      x1: el.getAttribute('x1') || 0,
      y1: el.getAttribute('y1') || 0,
      x2: el.getAttribute('x2') || '100%',
      y2: el.getAttribute('y2') || 0
    };
  }

  function getRadialCoords(el) {
    return {
      x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',
      y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',
      r1: 0,
      x2: el.getAttribute('cx') || '50%',
      y2: el.getAttribute('cy') || '50%',
      r2: el.getAttribute('r') || '50%'
    };
  }
  /* _FROM_SVG_END_ */

  /**
   * Gradient class
   * @class fabric.Gradient
   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#gradients}
   * @see {@link fabric.Gradient#initialize} for constructor definition
   */
  fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {
    /*
     * Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
     * @type Number
     * @default 0
     */
    origX: 0,

    /*
     * Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
     * @type Number
     * @default 0
     */
    origY: 0,

    /**
     * Constructor
     * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops
     * @return {fabric.Gradient} thisArg
     */
    initialize: function(options) {
      options || (options = { });

      var coords = { };

      this.id = fabric.Object.__uid++;
      this.type = options.type || 'linear';

      coords = {
        x1: options.coords.x1 || 0,
        y1: options.coords.y1 || 0,
        x2: options.coords.x2 || 0,
        y2: options.coords.y2 || 0
      };

      if (this.type === 'radial') {
        coords.r1 = options.coords.r1 || 0;
        coords.r2 = options.coords.r2 || 0;
      }

      this.coords = coords;
      this.gradientUnits = options.gradientUnits || 'objectBoundingBox';
      this.colorStops = options.colorStops.slice();
      if (options.gradientTransform) {
        this.gradientTransform = options.gradientTransform;
      }
      this.origX = options.left || this.origX;
      this.origY = options.top || this.origY;
    },

    /**
     * Adds another colorStop
     * @param {Object} colorStop Object with offset and color
     * @return {fabric.Gradient} thisArg
     */
    addColorStop: function(colorStop) {
      for (var position in colorStop) {
        var color = new fabric.Color(colorStop[position]);
        this.colorStops.push({
          offset: position,
          color: color.toRgb(),
          opacity: color.getAlpha()
        });
      }
      return this;
    },

    /**
     * Returns object representation of a gradient
     * @return {Object}
     */
    toObject: function() {
      return {
        type: this.type,
        coords: this.coords,
        gradientUnits: this.gradientUnits,
        colorStops: this.colorStops
      };
    },

    /* _TO_SVG_START_ */
    /**
     * Returns SVG representation of an gradient
     * @param {Object} object Object to create a gradient for
     * @param {Boolean} normalize Whether coords should be normalized
     * @return {String} SVG representation of an gradient (linear/radial)
     */
    toSVG: function(object, normalize) {
      var coords = fabric.util.object.clone(this.coords),
          markup, commonAttributes;

      // colorStops must be sorted ascending
      this.colorStops.sort(function(a, b) {
        return a.offset - b.offset;
      });

      if (normalize && this.gradientUnits === 'userSpaceOnUse') {
        coords.x1 += object.width / 2;
        coords.y1 += object.height / 2;
        coords.x2 += object.width / 2;
        coords.y2 += object.height / 2;
      }
      else if (this.gradientUnits === 'objectBoundingBox') {
        _convertValuesToPercentUnits(object, coords);
      }
      commonAttributes = 'id="SVGID_' + this.id +
                     '" gradientUnits="' + this.gradientUnits + '"';
      if (this.gradientTransform) {
        commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" ';
      }
      if (this.type === 'linear') {
        markup = [
          //jscs:disable validateIndentation
          '<linearGradient ',
            commonAttributes,
            ' x1="', coords.x1,
            '" y1="', coords.y1,
            '" x2="', coords.x2,
            '" y2="', coords.y2,
          '">\n'
          //jscs:enable validateIndentation
        ];
      }
      else if (this.type === 'radial') {
        markup = [
          //jscs:disable validateIndentation
          '<radialGradient ',
            commonAttributes,
            ' cx="', coords.x2,
            '" cy="', coords.y2,
            '" r="', coords.r2,
            '" fx="', coords.x1,
            '" fy="', coords.y1,
          '">\n'
          //jscs:enable validateIndentation
        ];
      }

      for (var i = 0; i < this.colorStops.length; i++) {
        markup.push(
          //jscs:disable validateIndentation
          '<stop ',
            'offset="', (this.colorStops[i].offset * 100) + '%',
            '" style="stop-color:', this.colorStops[i].color,
            (this.colorStops[i].opacity != null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
          '"/>\n'
          //jscs:enable validateIndentation
        );
      }

      markup.push((this.type === 'linear' ? '</linearGradient>\n' : '</radialGradient>\n'));

      return markup.join('');
    },
    /* _TO_SVG_END_ */

    /**
     * Returns an instance of CanvasGradient
     * @param {CanvasRenderingContext2D} ctx Context to render on
     * @return {CanvasGradient}
     */
    toLive: function(ctx) {
      var gradient;

      if (!this.type) {
        return;
      }

      if (this.type === 'linear') {
        gradient = ctx.createLinearGradient(
          this.coords.x1, this.coords.y1, this.coords.x2, this.coords.y2);
      }
      else if (this.type === 'radial') {
        gradient = ctx.createRadialGradient(
          this.coords.x1, this.coords.y1, this.coords.r1, this.coords.x2, this.coords.y2, this.coords.r2);
      }

      for (var i = 0, len = this.colorStops.length; i < len; i++) {
        var color = this.colorStops[i].color,
            opacity = this.colorStops[i].opacity,
            offset = this.colorStops[i].offset;

        if (typeof opacity !== 'undefined') {
          color = new fabric.Color(color).setAlpha(opacity).toRgba();
        }
        gradient.addColorStop(parseFloat(offset), color);
      }

      return gradient;
    }
  });

  fabric.util.object.extend(fabric.Gradient, {

    /* _FROM_SVG_START_ */
    /**
     * Returns {@link fabric.Gradient} instance from an SVG element
     * @static
     * @memberof fabric.Gradient
     * @param {SVGGradientElement} el SVG gradient element
     * @param {fabric.Object} instance
     * @return {fabric.Gradient} Gradient instance
     * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
     * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
     */
    fromElement: function(el, instance) {

      /**
       *  @example:
       *
       *  <linearGradient id="linearGrad1">
       *    <stop offset="0%" stop-color="white"/>
       *    <stop offset="100%" stop-color="black"/>
       *  </linearGradient>
       *
       *  OR
       *
       *  <linearGradient id="linearGrad2">
       *    <stop offset="0" style="stop-color:rgb(255,255,255)"/>
       *    <stop offset="1" style="stop-color:rgb(0,0,0)"/>
       *  </linearGradient>
       *
       *  OR
       *
       *  <radialGradient id="radialGrad1">
       *    <stop offset="0%" stop-color="white" stop-opacity="1" />
       *    <stop offset="50%" stop-color="black" stop-opacity="0.5" />
       *    <stop offset="100%" stop-color="white" stop-opacity="1" />
       *  </radialGradient>
       *
       *  OR
       *
       *  <radialGradient id="radialGrad2">
       *    <stop offset="0" stop-color="rgb(255,255,255)" />
       *    <stop offset="0.5" stop-color="rgb(0,0,0)" />
       *    <stop offset="1" stop-color="rgb(255,255,255)" />
       *  </radialGradient>
       *
       */

      var colorStopEls = el.getElementsByTagName('stop'),
          type = (el.nodeName === 'linearGradient' ? 'linear' : 'radial'),
          gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',
          gradientTransform = el.getAttribute('gradientTransform'),
          colorStops = [],
          coords = { };

      if (type === 'linear') {
        coords = getLinearCoords(el);
      }
      else if (type === 'radial') {
        coords = getRadialCoords(el);
      }

      for (var i = colorStopEls.length; i--; ) {
        colorStops.push(getColorStop(colorStopEls[i]));
      }

      _convertPercentUnitsToValues(instance, coords);

      var gradient = new fabric.Gradient({
        type: type,
        coords: coords,
        gradientUnits: gradientUnits,
        colorStops: colorStops
      });

      if (gradientTransform) {
        gradient.gradientTransform = fabric.parseTransformAttribute(gradientTransform);
      }

      return gradient;
    },
    /* _FROM_SVG_END_ */

    /**
     * Returns {@link fabric.Gradient} instance from its object representation
     * @static
     * @memberof fabric.Gradient
     * @param {Object} obj
     * @param {Object} [options] Options object
     */
    forObject: function(obj, options) {
      options || (options = { });
      _convertPercentUnitsToValues(obj, options);
      return new fabric.Gradient(options);
    }
  });

  /**
   * @private
   */
  function _convertPercentUnitsToValues(object, options) {
    for (var prop in options) {
      if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
        var percents = parseFloat(options[prop], 10);
        if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
          options[prop] = fabric.util.toFixed(object.width * percents / 100, 2)  + object.left;
        }
        else if (prop === 'y1' || prop === 'y2') {
          options[prop] = fabric.util.toFixed(object.height * percents / 100, 2) + object.top;
        }
      }
    }
  }

  /* _TO_SVG_START_ */
  /**
   * @private
   */
  function _convertValuesToPercentUnits(object, options) {
    for (var prop in options) {
      //convert to percent units
      if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
        options[prop] = fabric.util.toFixed((options[prop] - object.fill.origX) / object.width * 100, 2) + '%';
      }
      else if (prop === 'y1' || prop === 'y2') {
        options[prop] = fabric.util.toFixed((options[prop] - object.fill.origY) / object.height * 100, 2) + '%';
      }
    }
  }
  /* _TO_SVG_END_ */

})();
<|endoftext|>


<commit_before>ChartAPI.Graph.css = {};

ChartAPI.Graph.css.Base = function (data, config) {
  this.len = data.length;
  this.$graphEl = $('
');
};

ChartAPI.Graph.css.Base.prototype.remove = function () {
  this.$graphEl.remove();
};

ChartAPI.Graph.css.Base.prototype.horizontalBar = function (data, config, range, $container) {
  if (config.width) {
    this.$graphEl.css({
      'width': config.width,
      'max-width': '100%',
      'margin': '0 auto'
    });
  }

  var barColor = config.barColor || ChartAPI.Graph.getCachedChartColors(config.id, null, config.chartColorsMethod)[1],
    barBackgroundColor = config.barBackgroundColor || '#f0f0f0',
    dateColor = config.dateColor || '#999999',
    dateColorSaturday = config.dateColorSaturday || dateColor,
    dateColorSunday = config.dateColorSunday || dateColor,
    labelColor = config.labelColor || '#999999',
    barWidth = parseInt(config.barWidth, 10) || 30,
    barInterval = parseInt(config.barInterval, 10) || 5,
    labelSize = parseInt(config.labelSize, 10) || barWidth * 0.45,
    createCSSGraphBarEl = function () {
      return $('

');
    },
    dataY = $.map(data, function (d) {
      return parseInt(d.y, 10);
    }),
    label = $.map(data, function (d) {
      return {
        value: parseInt(d.x.substr(d.x.lastIndexOf('-') + 1), 10).toString(),
        weekday: ChartAPI.Date.parse(d.x) ? ChartAPI.Date.parse(d.x).getDay() : null
      }
    }),
    maxY = Math.max.apply(null, dataY) || 1,
    yLabel = config.yLabel || dataY,
    width, $el, $background, $bar, $count, $date;

  for (var i = this.len; i > 0;) {
    i = i - 1;
    width = Math.floor((dataY[i] / maxY) * 100) - 15;
    $el = createCSSGraphBarEl();
    $background = $el.find('.css-graph-bar-background');
    $background.css({
      'background-color': barBackgroundColor
    });

    if (config.showDate) {
      $date = $el.find('.css-graph-date');
      $date.text(label[i].value).css({
        'color': dateColor,
        'font-size': labelSize + 'px',
        'line-height': barWidth + 'px'
      });
      if (label[i].weekday === 6) {
        $date.addClass('saturday').css({
          'color': dateColorSaturday
        });
      } else if (label[i].weekday === 0) {
        $date.addClass('sunday').css({
          'color': dateColorSunday
        })
      }

      $el.find('.css-graph-bar-container').css({
        'margin-left': barWidth + 'px'
      });
    }

    $bar = $el.find('.css-graph-bar');
    $bar.css({
      'width': width + '%',
      'background-color': barColor
    });
    $count = $el.find('.css-graph-bar-count');
    $count.text(yLabel[i]).css({
      'color': labelColor,
      'font-size': labelSize + 'px',
      'line-height': barWidth + 'px'
    });
    $el.appendTo(this.$graphEl);
  }

  this.$graphEl.appendTo($container);
};

ChartAPI.Graph.css.Base.prototype.ratioHorizontalBar = function (data, config, range, $container) {
  var yLength = config.yLength,
    barWidth = parseInt(config.barWidth, 10) || 30,
    barInterval = parseInt(config.barInterval, 10) || 5,
    labelSize = parseInt(config.labelSize, 10) || barWidth * 0.45,
    dateColor = config.dateColor || '#999999',
    barColors = config.barColors || ChartAPI.Graph.getCachedChartColors(config.id, null, config.chartColorsMethod),
    labelColors = config.labelColors,
    labelClasses = config.labelClasses,
    i, j,
    d, dataY, totalY, $barContainer, $el, $bar, label, $date, width, totalWidth;

  for (i = 0; i < this.len; i++) {
    d = data[i];
    dataY = [];
    totalY = 0;
    totalWidth = 0;
    for (j = 0; j < yLength; j++) {
      dataY.push(d['y' + (j || '')]);
      totalY = totalY + parseInt(d['y' + (j || '')], 10);
    }

    $barContainer = $('

').appendTo(this.$graphEl);
    if (config.showDate && d.x) {
      label = parseInt(d.x.substr(d.x.lastIndexOf('-') + 1), 10).toString();
      $date = $('
' + label + '
').appendTo($barContainer);
    }

    $el = $('

').appendTo($barContainer);

    if (config.showDate) {
      $el.css({
        'margin-left': barWidth + 'px'
      });
    }

    for (j = 0; j < yLength; j++) {
      width = Math.floor((dataY[j] / totalY) * 1000) / 10;

      if (width) {
        if (yLength === j) {
          width = 100 - totalWidth;
        }
        totalWidth = totalWidth + width;

        $bar = $('

');
        $bar.css({
          'width': width + '%',
          'background-color': barColors[j]
        });

        if (config.showCount) {
          $bar.text(dataY[j]);
        }

        if (labelClasses && labelClasses[j]) {
          $bar.addClass(labelClasses[j]);
        }

        if (labelColors && labelColors[j]) {
          $bar.css({
            'color': labelColors[j]
          });
        }

        $bar.appendTo($el);
      }
    }

    $el.appendTo($barContainer);
  }
  this.$graphEl.appendTo($container);
};

ChartAPI.Graph.css.horizontalBar = ChartAPI.Graph.css.ratioHorizontalBar = function (data, config, range, $container) {
  var cssGraph = new ChartAPI.Graph.css.Base(data, config, range, $container);
  var method = config.type.slice(config.type.lastIndexOf('.') + 1);
  cssGraph[method](data, config, range, $container);
  return cssGraph;
};
<commit_msg>enabled to set margin left and date label size separately<commit_after>ChartAPI.Graph.css = {};

ChartAPI.Graph.css.Base = function (data, config) {
  this.len = data.length;
  this.$graphEl = $('
');
};

ChartAPI.Graph.css.Base.prototype.remove = function () {
  this.$graphEl.remove();
};

ChartAPI.Graph.css.Base.prototype.horizontalBar = function (data, config, range, $container) {
  if (config.width) {
    this.$graphEl.css({
      'width': config.width,
      'max-width': '100%',
      'margin': '0 auto'
    });
  }

  var barColor = config.barColor || ChartAPI.Graph.getCachedChartColors(config.id, null, config.chartColorsMethod)[1],
    barBackgroundColor = config.barBackgroundColor || '#f0f0f0',
    dateColor = config.dateColor || '#999999',
    dateColorSaturday = config.dateColorSaturday || dateColor,
    dateColorSunday = config.dateColorSunday || dateColor,
    labelColor = config.labelColor || '#999999',
    barWidth = parseInt(config.barWidth, 10) || 30,
    barMarginLeft = parseInt(config.barMarginLeft, 10) || 30,
    barInterval = parseInt(config.barInterval, 10) || 5,
    labelSize = parseInt(config.labelSize, 10) || barWidth * 0.45,
    dateLabelSize = parseInt(config.dateLabelSize, 10) || labelSize,
    createCSSGraphBarEl = function () {
      return $('

');
    },
    dataY = $.map(data, function (d) {
      return parseInt(d.y, 10);
    }),
    label = $.map(data, function (d) {
      return {
        value: parseInt(d.x.substr(d.x.lastIndexOf('-') + 1), 10).toString(),
        weekday: ChartAPI.Date.parse(d.x) ? ChartAPI.Date.parse(d.x).getDay() : null
      }
    }),
    maxY = Math.max.apply(null, dataY) || 1,
    yLabel = config.yLabel || dataY,
    width, $el, $background, $bar, $count, $date;

  for (var i = this.len; i > 0;) {
    i = i - 1;
    width = Math.floor((dataY[i] / maxY) * 100) - 15;
    $el = createCSSGraphBarEl();
    $background = $el.find('.css-graph-bar-background');
    $background.css({
      'background-color': barBackgroundColor
    });

    if (config.showDate) {
      $date = $el.find('.css-graph-date');
      $date.text(label[i].value).css({
        'color': dateColor,
        'font-size': dateLabelSize + 'px',
        'line-height': barWidth + 'px'
      });
      if (label[i].weekday === 6) {
        $date.addClass('saturday').css({
          'color': dateColorSaturday
        });
      } else if (label[i].weekday === 0) {
        $date.addClass('sunday').css({
          'color': dateColorSunday
        })
      }

      $el.find('.css-graph-bar-container').css({
        'margin-left': barMarginLeft + 'px'
      });
    }

    $bar = $el.find('.css-graph-bar');
    $bar.css({
      'width': width + '%',
      'background-color': barColor
    });
    $count = $el.find('.css-graph-bar-count');
    $count.text(yLabel[i]).css({
      'color': labelColor,
      'font-size': labelSize + 'px',
      'line-height': barWidth + 'px'
    });
    $el.appendTo(this.$graphEl);
  }

  this.$graphEl.appendTo($container);
};

ChartAPI.Graph.css.Base.prototype.ratioHorizontalBar = function (data, config, range, $container) {
  var yLength = config.yLength,
    barWidth = parseInt(config.barWidth, 10) || 30,
    barMarginLeft = parseInt(config.barMarginLeft, 10) || 30,
    barInterval = parseInt(config.barInterval, 10) || 5,
    labelSize = parseInt(config.labelSize, 10) || barWidth * 0.45,
    dateColor = config.dateColor || '#999999',
    barColors = config.barColors || ChartAPI.Graph.getCachedChartColors(config.id, null, config.chartColorsMethod),
    labelColors = config.labelColors,
    labelClasses = config.labelClasses,
    i, j,
    d, dataY, totalY, $barContainer, $el, $bar, label, $date, width, totalWidth;

  for (i = 0; i < this.len; i++) {
    d = data[i];
    dataY = [];
    totalY = 0;
    totalWidth = 0;
    for (j = 0; j < yLength; j++) {
      dataY.push(d['y' + (j || '')]);
      totalY = totalY + parseInt(d['y' + (j || '')], 10);
    }

    $barContainer = $('

').appendTo(this.$graphEl);
    if (config.showDate && d.x) {
      label = parseInt(d.x.substr(d.x.lastIndexOf('-') + 1), 10).toString();
      $date = $('
' + label + '
').appendTo($barContainer);
    }

    $el = $('

').appendTo($barContainer);

    if (config.showDate) {
      $el.css({
        'margin-left': barMarginLeft + 'px'
      });
    }

    for (j = 0; j < yLength; j++) {
      width = Math.floor((dataY[j] / totalY) * 1000) / 10;

      if (width) {
        if (yLength === j) {
          width = 100 - totalWidth;
        }
        totalWidth = totalWidth + width;

        $bar = $('

');
        $bar.css({
          'width': width + '%',
          'background-color': barColors[j]
        });

        if (config.showCount) {
          $bar.text(dataY[j]);
        }

        if (labelClasses && labelClasses[j]) {
          $bar.addClass(labelClasses[j]);
        }

        if (labelColors && labelColors[j]) {
          $bar.css({
            'color': labelColors[j]
          });
        }

        $bar.appendTo($el);
      }
    }

    $el.appendTo($barContainer);
  }
  this.$graphEl.appendTo($container);
};

ChartAPI.Graph.css.horizontalBar = ChartAPI.Graph.css.ratioHorizontalBar = function (data, config, range, $container) {
  var cssGraph = new ChartAPI.Graph.css.Base(data, config, range, $container);
  var method = config.type.slice(config.type.lastIndexOf('.') + 1);
  cssGraph[method](data, config, range, $container);
  return cssGraph;
};
<|endoftext|>


<commit_before>/*global Phaser*/
/* hexagonal A* pathfinding following http://www.policyalmanac.org/games/aStarTutorial.htm */

var game = new Phaser.Game(600, 1000, Phaser.AUTO, 'TutContainer', { preload: preload, create: create});

var block1=
[
[0,1,0],
[1,1,1],
[0,0,0]];
var block2=
[
[0,0,0],
[1,1,1],
[0,0,0]];
var block3=
[
[0,1,0],
[0,1,1],
[0,0,0]];
var block4=
[
[0,1,0],
[0,1,1],
[0,1,0]];
var block5=
[
[0,1,0],
[1,1,0],
[0,1,0]];
var block6=
[
[0,0,0],
[1,1,1],
[1,0,1]];
var block7=
[
[0,1,0],
[0,1,0],
[0,1,0]];

var currentBlock=
[
[0,0,0],
[0,0,0],
[0,0,0]];

var levelData=
[
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0]
];

var bmpText;
var hexTileHeight=52;
var hexTileWidth=61;
var infoTxt;
var gameScene;//this is the render texture onto which we draw level
var hexSprite;
var aKey;
var dKey;
var sKey;
var zKey;
var xKey;
var score;
var clockWise=true;

var verticalOffset=hexTileHeight;
var horizontalOffset=hexTileWidth*3/4;
var startX;
var startY;
var startXInit=hexTileWidth/2;
var startYInit=hexTileHeight/2;
var axialPoint= new Phaser.Point();
var cubicZ;

var blockRowValue;
var blockMidColumnValue;

function preload() {
    //load all necessary assets
    game.load.bitmapFont('font', 'assets/font.png', 'assets/font.xml');
    game.load.image('hex', 'assets/hexsmall.png');
}

function create() {
    bmpText = game.add.bitmapText(10, 10, 'font', 'Tetris\nTap A/D to move block\nTap Z/X to rotate block\nTap S to drop', 18);
    game.stage.backgroundColor = '#cccccc';
    xKey=game.input.keyboard.addKey(Phaser.Keyboard.X);
    xKey.onUp.add(rotateClockWise);
    zKey=game.input.keyboard.addKey(Phaser.Keyboard.Z);
    zKey.onUp.add(rotateAntiClockWise);
    aKey=game.input.keyboard.addKey(Phaser.Keyboard.A);
    aKey.onUp.add(moveLeft);
    dKey=game.input.keyboard.addKey(Phaser.Keyboard.D);
    dKey.onUp.add(moveRight);
    sKey=game.input.keyboard.addKey(Phaser.Keyboard.S);
    sKey.onUp.add(dropDown);

    hexSprite= game.make.sprite(0, 0, 'hex');
    hexSprite.anchor.setTo(0.5, 0.5);

    hexSprite.rotation=Math.PI/2;

    gameScene=game.add.renderTexture(600,1000);
    game.add.sprite(40, 100, gameScene);
    infoTxt=game.add.text(300,40,'0');
    infoTxt.anchor.setTo(0.5, 0.5);

    // Maintain aspect ratio
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    score=0;

    releaseBlock();
    renderScene();
}
function renderScene(){
    paintBlock();
    gameScene.clear();//clear the previous frame then draw again

    for (var i = 0; i < levelData.length; i++)
    {
        startX=startXInit;
        startY=2*startYInit+(i*verticalOffset);
        for (var j = 0; j < levelData[0].length; j++)
        {
            if(j%2!=0){
                startY=startY+startYInit;
            }else{
                startY=startY-startYInit;
            }
            axialPoint.x=i;
            axialPoint.y=j;
            hexSprite.tint='0xffffff';
            if(levelData[i][j]>-1){
                axialPoint=offsetToAxial(axialPoint);
                cubicZ=calculateCubicZ(axialPoint);
                if(levelData[i][j]>0){
                    hexSprite.tint='0xff0000';
                }
                gameScene.renderXY(hexSprite,startX, startY, false);
            }
            startX+=horizontalOffset;
        }

    }
}
function paintBlock(erase){
    var startI=blockRowValue;
    var startJ=blockMidColumnValue-1;
    var q=0;
    var r=0
    for (var i = startI; i < startI+3; i++){
        for (var j = startJ; j < startJ+3; j++)
        {
            if(blockMidColumnValue%2==0 && j%2!=0){
                if(i-1<0||j<0)continue;
                if(erase){
                    levelData[i-1][j]=0;
                }else{
                    levelData[i-1][j]=currentBlock[q][r];
                }
            }else{
                if(i<0||j<0)continue;
               if(erase){
                    levelData[i][j]=0;
                }else{
                    levelData[i][j]=currentBlock[q][r];
                }
            }
            r++
        }
        q++;
        r=0;
    }
}

function releaseBlock(){
    blockRowValue=0;
    blockMidColumnValue=5;
    var whichBlock= Math.floor(1+(Math.random()*7));
    switch (whichBlock) {//assign blocks
        case 1:
            currentBlock=block1;
            break;
        case 2:
            currentBlock=block2;
            //blockRowValue=-1;
            break;
        case 3:
            currentBlock=block3;
            break;
        case 4:
            currentBlock=block4;
            break;
        case 5:
            currentBlock=block5;
            break;
        case 6:
            currentBlock=block6;
            //blockRowValue=-1;
            break;
        case 7:
            currentBlock=block7;
            break;
        default:

    }
}
function moveLeft(){
    paintBlock(true);
    blockMidColumnValue--;
    renderScene();
}
function moveRight(){
    paintBlock(true);
    blockMidColumnValue++;
    renderScene();
}
function dropDown(){
    paintBlock(true);
    blockRowValue++;
    renderScene();
}
function rotateClockWise(){
    clockWise=true;
    rotateBlock();
    renderScene();
}
function rotateAntiClockWise(){
    clockWise=false;
    rotateBlock();
    renderScene();
}
function rotateBlock(){
    var numRotations=1;//rotate once
    var midPoint=new Phaser.Point(1,1);
    var newBlockData=
    [
    [0,0,0],
    [0,1,0],
    [0,0,0]
    ];

    var rotatingTile=new Phaser.Point();
    for (var i = 0; i < currentBlock.length; i++){
            for (var j = 0; j < currentBlock[0].length; j++)
            {
                if(currentBlock[i][j]==1){//find every solid tile & rotate
                    rotatingTile.x=i;
                    rotatingTile.y=j;
                    for (var k = 0; k < numRotations; k++)
                    {
                        rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
                    }
                    newBlockData[rotatingTile.x][rotatingTile.y]=1;//populate new blockArray
                }
            }
    }
    currentBlock=newBlockData;
}
function rotateTileAroundTile(tileToRotate, anchorTile){
    tileToRotate=offsetToAxial(tileToRotate);//convert to axial
    var tileToRotateZ=calculateCubicZ(tileToRotate);//find z value
    anchorTile=offsetToAxial(anchorTile);//convert to axial
    var anchorTileZ=calculateCubicZ(anchorTile);//find z value
    tileToRotate.x=tileToRotate.x-anchorTile.x;//find x difference
    tileToRotate.y=tileToRotate.y-anchorTile.y;//find y difference
    tileToRotateZ=tileToRotateZ-anchorTileZ;//find z difference
    var pointArr=[tileToRotate.x,tileToRotate.y,tileToRotateZ];//populate array to rotate
    pointArr=arrayRotate(pointArr,clockWise);//rotate array, true for clockwise
    tileToRotate.x=(-1*pointArr[0])+anchorTile.x;//multiply by -1 & remove the x difference
    tileToRotate.y=(-1*pointArr[1])+anchorTile.y;//multiply by -1 & remove the y difference
    tileToRotate=axialToOffset(tileToRotate);//convert to offset
    return tileToRotate;
}
function offsetToAxial(offsetPt){
    offsetPt.x=(offsetPt.x-(Math.floor(offsetPt.y/2)));//display x = coordinate x' - floor(y/2)
    return offsetPt;
}
function axialToOffset(axialPt){
    axialPt.x=(axialPt.x+(Math.floor(axialPt.y/2)));//coordinate x = display x' + floor(y/2)
    return axialPt;
}
function calculateCubicZ(newAxialPoint){
    return -newAxialPoint.x-newAxialPoint.y;
}
function arrayRotate(arr, reverse){//nifty method to rotate array elements
  if(reverse)
    arr.unshift(arr.pop())
  else
    arr.push(arr.shift())
  return arr
} <commit_msg>block paint logic changed to use cubic<commit_after>/*global Phaser*/
/* hexagonal A* pathfinding following http://www.policyalmanac.org/games/aStarTutorial.htm */

var game = new Phaser.Game(600, 1000, Phaser.AUTO, 'TutContainer', { preload: preload, create: create});

function BlockData(topB,topRightB,bottomRightB,bottomB,bottomLeftB,topLeftB){
    this.tBlock=topB;
    this.trBlock=topRightB;
    this.brBlock=bottomRightB;
    this.bBlock=bottomB;
    this.blBlock=bottomLeftB;
    this.tlBlock=topLeftB;
    this.mBlock=1;
}

var block1= new BlockData(1,1,0,0,0,1);

var block2= new BlockData(0,1,0,0,0,1);

var block3= new BlockData(1,1,0,0,0,0);

var block4= new BlockData(1,1,0,1,0,0);

var block5= new BlockData(1,0,0,1,0,1);

var block6= new BlockData(0,1,1,0,1,1);

var block7= new BlockData(1,0,0,1,0,0);

var currentBlock= new BlockData(0,0,0,0,0,0);

var levelData=
[
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0]
];

var bmpText;
var hexTileHeight=52;
var hexTileWidth=61;
var infoTxt;
var gameScene;//this is the render texture onto which we draw level
var hexSprite;
var aKey;
var dKey;
var sKey;
var zKey;
var xKey;
var score;
var clockWise=true;

var verticalOffset=hexTileHeight;
var horizontalOffset=hexTileWidth*3/4;
var startX;
var startY;
var startXInit=hexTileWidth/2;
var startYInit=hexTileHeight/2;
var axialPoint= new Phaser.Point();
var cubicZ;

var blockRowValue;
var blockMidColumnValue;

function preload() {
    //load all necessary assets
    game.load.bitmapFont('font', 'assets/font.png', 'assets/font.xml');
    game.load.image('hex', 'assets/hexsmall.png');
}

function create() {
    bmpText = game.add.bitmapText(10, 10, 'font', 'Tetris\nTap A/D to move block\nTap Z/X to rotate block\nTap S to drop', 18);
    game.stage.backgroundColor = '#cccccc';
    xKey=game.input.keyboard.addKey(Phaser.Keyboard.X);
    xKey.onUp.add(rotateClockWise);
    zKey=game.input.keyboard.addKey(Phaser.Keyboard.Z);
    zKey.onUp.add(rotateAntiClockWise);
    aKey=game.input.keyboard.addKey(Phaser.Keyboard.A);
    aKey.onUp.add(moveLeft);
    dKey=game.input.keyboard.addKey(Phaser.Keyboard.D);
    dKey.onUp.add(moveRight);
    sKey=game.input.keyboard.addKey(Phaser.Keyboard.S);
    sKey.onUp.add(dropDown);

    hexSprite= game.make.sprite(0, 0, 'hex');
    hexSprite.anchor.setTo(0.5, 0.5);

    hexSprite.rotation=Math.PI/2;

    gameScene=game.add.renderTexture(600,1000);
    game.add.sprite(40, 100, gameScene);
    infoTxt=game.add.text(300,40,'0');
    infoTxt.anchor.setTo(0.5, 0.5);

    // Maintain aspect ratio
    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    score=0;

    releaseBlock();
    renderScene();
}
function renderScene(){
    paintBlock();
    gameScene.clear();//clear the previous frame then draw again

    for (var i = 0; i < levelData.length; i++)
    {
        startX=startXInit;
        startY=2*startYInit+(i*verticalOffset);
        for (var j = 0; j < levelData[0].length; j++)
        {
            if(j%2!=0){
                startY=startY+startYInit;
            }else{
                startY=startY-startYInit;
            }
            axialPoint.x=i;
            axialPoint.y=j;
            hexSprite.tint='0xffffff';
            if(levelData[i][j]>-1){
                axialPoint=offsetToAxial(axialPoint);
                cubicZ=calculateCubicZ(axialPoint);
                if(levelData[i][j]>0){
                    hexSprite.tint='0xff0000';
                }
                gameScene.renderXY(hexSprite,startX, startY, false);
            }
            startX+=horizontalOffset;
        }

    }
}
/*
//this one uses array coordinates, so we need to check for odd/even columns
function paintBlock(erase){
    var currentBlockData=arrayFromBlock(currentBlock);
    var startI=blockRowValue;
    var startJ=blockMidColumnValue-1;
    var q=0;
    var r=0
    for (var i = startI; i < startI+3; i++){
        for (var j = startJ; j < startJ+3; j++)
        {
            if(blockMidColumnValue%2==0 && j%2!=0){
                if(i-1<0||j<0)continue;
                if(erase){
                    levelData[i-1][j]=0;
                }else{
                    levelData[i-1][j]=currentBlockData[q][r];
                }
            }else{
                if(i<0||j<0)continue;
               if(erase){
                    levelData[i][j]=0;
                }else{
                    levelData[i][j]=currentBlockData[q][r];
                }
            }
            r++
        }
        q++;
        r=0;
    }
}
*/
//let us use cubic coordinates to simplify it
function paintBlock(erase){
    var store=clockWise;
    clockWise=true;
    if(erase){//mid
        levelData[blockRowValue+1][blockMidColumnValue]=0;
    }else{
        levelData[blockRowValue+1][blockMidColumnValue]=1;
    }
    var rotatingTile=new Phaser.Point(blockRowValue,blockMidColumnValue);
    if(erase){//top
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.tBlock;
    }
    var midPoint=new Phaser.Point(blockRowValue+1,blockMidColumnValue);
    rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
    if(erase){//tr
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.trBlock;
    }
    midPoint.x=blockRowValue+1;
    midPoint.y=blockMidColumnValue;
    rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
    if(erase){//br
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.brBlock;
    }
    midPoint.x=blockRowValue+1;
    midPoint.y=blockMidColumnValue;
    rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
    if(erase){//b
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.bBlock;
    }
    midPoint.x=blockRowValue+1;
    midPoint.y=blockMidColumnValue;
    rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
    if(erase){//bl
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.blBlock;
    }
    midPoint.x=blockRowValue+1;
    midPoint.y=blockMidColumnValue;
    rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
    if(erase){//tl
        levelData[rotatingTile.x][rotatingTile.y]=0;
    }else{
        levelData[rotatingTile.x][rotatingTile.y]=currentBlock.tlBlock;
    }
    clockWise=store;
}
function releaseBlock(){
    blockRowValue=0;
    blockMidColumnValue=5;
    var whichBlock= Math.floor(1+(Math.random()*7));
    //whichBlock=2;
    switch (whichBlock) {//assign blocks
        case 1:
            currentBlock=block1;
            break;
        case 2:
            currentBlock=block2;
            //blockRowValue=-1;
            break;
        case 3:
            currentBlock=block3;
            break;
        case 4:
            currentBlock=block4;
            break;
        case 5:
            currentBlock=block5;
            break;
        case 6:
            currentBlock=block6;
            //blockRowValue=-1;
            break;
        case 7:
            currentBlock=block7;
            break;
        default:

    }
    console.log(whichBlock);
}
function moveLeft(){
    paintBlock(true);
    blockMidColumnValue--;
    renderScene();
}
function moveRight(){
    paintBlock(true);
    blockMidColumnValue++;
    renderScene();
}
function dropDown(){
    paintBlock(true);
    blockRowValue++;
    renderScene();
}
function rotateClockWise(){
    clockWise=true;
    rotateBlock();
    renderScene();
}
function rotateAntiClockWise(){
    clockWise=false;
    rotateBlock();
    renderScene();
}
function rotateBlock(){
    var numRotations=1;//rotate once
    var midPoint=new Phaser.Point(1,1);
    var newBlockData=
    [
    [0,0,0],
    [0,1,0],
    [0,0,0]
    ];
    var currentBlockData=arrayFromBlock(currentBlock);

    var rotatingTile=new Phaser.Point();
    for (var i = 0; i < currentBlockData.length; i++){
            for (var j = 0; j < currentBlockData[0].length; j++)
            {
                if(currentBlockData[i][j]==1){//find every solid tile & rotate
                    rotatingTile.x=i;
                    rotatingTile.y=j;
                    for (var k = 0; k < numRotations; k++)
                    {
                        rotatingTile=rotateTileAroundTile(rotatingTile,midPoint);
                    }
                    newBlockData[rotatingTile.x][rotatingTile.y]=1;//populate new blockArray
                }
            }
    }
    currentBlock=blockFromArray(newBlockData);
}
function rotateTileAroundTile(tileToRotate, anchorTile){
    tileToRotate=offsetToAxial(tileToRotate);//convert to axial
    var tileToRotateZ=calculateCubicZ(tileToRotate);//find z value
    anchorTile=offsetToAxial(anchorTile);//convert to axial
    var anchorTileZ=calculateCubicZ(anchorTile);//find z value
    tileToRotate.x=tileToRotate.x-anchorTile.x;//find x difference
    tileToRotate.y=tileToRotate.y-anchorTile.y;//find y difference
    tileToRotateZ=tileToRotateZ-anchorTileZ;//find z difference
    var pointArr=[tileToRotate.x,tileToRotate.y,tileToRotateZ];//populate array to rotate
    pointArr=arrayRotate(pointArr,clockWise);//rotate array, true for clockwise
    tileToRotate.x=(-1*pointArr[0])+anchorTile.x;//multiply by -1 & remove the x difference
    tileToRotate.y=(-1*pointArr[1])+anchorTile.y;//multiply by -1 & remove the y difference
    tileToRotate=axialToOffset(tileToRotate);//convert to offset
    return tileToRotate;
}
function offsetToAxial(offsetPt){
    offsetPt.x=(offsetPt.x-(Math.floor(offsetPt.y/2)));//display x = coordinate x' - floor(y/2)
    return offsetPt;
}
function axialToOffset(axialPt){
    axialPt.x=(axialPt.x+(Math.floor(axialPt.y/2)));//coordinate x = display x' + floor(y/2)
    return axialPt;
}
function calculateCubicZ(newAxialPoint){
    return -newAxialPoint.x-newAxialPoint.y;
}
function arrayRotate(arr, reverse){//nifty method to rotate array elements
  if(reverse)
    arr.unshift(arr.pop())
  else
    arr.push(arr.shift())
  return arr
}
function blockFromArray(arrayToConvert){
    return new BlockData(
        arrayToConvert[0][1],
        arrayToConvert[1][2],
        arrayToConvert[2][2],
        arrayToConvert[2][1],
        arrayToConvert[2][0],
        arrayToConvert[1][0]
    );
}
function arrayFromBlock(blockToConvert){
    var newBlockData=
    [
    [0,0,0],
    [0,1,0],
    [0,0,0]
    ];
    newBlockData[0][1]=blockToConvert.tBlock;
    newBlockData[1][2]=blockToConvert.trBlock;
    newBlockData[2][2]=blockToConvert.brBlock;
    newBlockData[2][1]=blockToConvert.bBlock;
    newBlockData[2][0]=blockToConvert.blBlock;
    newBlockData[1][0]=blockToConvert.tlBlock;
    return newBlockData;
}<|endoftext|>


<commit_before>var _ = require('../util')
var Observer = require('../observer')
var Binding = require('../binding')

/**
 * Setup the scope of an instance, which contains:
 * - observed data
 * - computed properties
 * - user methods
 * - meta properties
 */

exports._initScope = function () {
  this._initData()
  this._initComputed()
  this._initMethods()
  this._initMeta()
}

/**
 * Initialize the data.
 */

exports._initData = function () {
  // proxy data on instance
  var data = this._data
  var keys = Object.keys(data)
  var i = keys.length
  var key
  while (i--) {
    key = keys[i]
    if (!_.isReserved(key)) {
      this._proxy(key)
    }
  }
  // observe data
  Observer.create(data).addVm(this)
}

/**
 * Swap the isntance's $data. Called in $data's setter.
 *
 * @param {Object} newData
 */

exports._setData = function (newData) {
  var oldData = this._data
  this._data = newData
  var keys, key, i
  // unproxy keys not present in new data
  keys = Object.keys(oldData)
  i = keys.length
  while (i--) {
    key = keys[i]
    if (!_.isReserved(key) && !(key in newData)) {
      this._unproxy(key)
    }
  }
  // proxy keys not already proxied,
  // and trigger change for changed values
  keys = Object.keys(newData)
  i = keys.length
  while (i--) {
    key = keys[i]
    if (!this.hasOwnProperty(key) && !_.isReserved(key)) {
      // new property
      this._proxy(key)
    }
  }
  oldData.__ob__.removeVm(this)
  Observer.create(newData).addVm(this)
  this._digest()
}

/**
 * Proxy a property, so that
 * vm.prop === vm._data.prop
 *
 * @param {String} key
 */

exports._proxy = function (key) {
  // need to store ref to self here
  // because these getter/setters might
  // be called by child instances!
  var self = this
  Object.defineProperty(self, key, {
    configurable: true,
    enumerable: true,
    get: function proxyGetter () {
      return self._data[key]
    },
    set: function proxySetter (val) {
      self._data[key] = val
    }
  })
}

/**
 * Unproxy a property.
 *
 * @param {String} key
 */

exports._unproxy = function (key) {
  delete this[key]
}

/**
 * Force update on every watcher in scope.
 */

exports._digest = function () {
  var i = this._watcherList.length
  while (i--) {
    this._watcherList[i].update()
  }
  var children = this._children
  var child
  if (children) {
    i = children.length
    while (i--) {
      child = children[i]
      if (child.$options.inherit) {
        child._digest()
      }
    }
  }
}

/**
 * Setup computed properties. They are essentially
 * special getter/setters
 */

function noop () {}
exports._initComputed = function () {
  var computed = this.$options.computed
  if (computed) {
    for (var key in computed) {
      var userDef = computed[key]
      var def = {
        enumerable: true,
        configurable: true
      }
      if (typeof userDef === 'function') {
        def.get = _.bind(userDef, this)
        def.set = noop
      } else {
        def.get = userDef.get
          ? _.bind(userDef.get, this)
          : noop
        def.set = userDef.set
          ? _.bind(userDef.set, this)
          : noop
      }
      Object.defineProperty(this, key, def)
    }
  }
}

/**
 * Setup instance methods. Methods must be bound to the
 * instance since they might be called by children
 * inheriting them.
 */

exports._initMethods = function () {
  var methods = this.$options.methods
  if (methods) {
    for (var key in methods) {
      this[key] = _.bind(methods[key], this)
    }
  }
}

/**
 * Initialize meta information like $index, $key & $value.
 */

exports._initMeta = function () {
  var metas = this.$options._meta
  if (metas) {
    for (var key in metas) {
      this._defineMeta(key, metas[key])
    }
  }
}

/**
 * Define a meta property, e.g $index, $key, $value
 * which only exists on the vm instance but not in $data.
 *
 * @param {String} key
 * @param {*} value
 */

exports._defineMeta = function (key, value) {
  var binding = new Binding()
  Object.defineProperty(this, key, {
    enumerable: true,
    configurable: true,
    get: function metaGetter () {
      if (Observer.target) {
        Observer.target.addDep(binding)
      }
      return value
    },
    set: function metaSetter (val) {
      if (val !== value) {
        value = val
        binding.notify()
      }
    }
  })
}<commit_msg>handle setting $data to null<commit_after>var _ = require('../util')
var Observer = require('../observer')
var Binding = require('../binding')

/**
 * Setup the scope of an instance, which contains:
 * - observed data
 * - computed properties
 * - user methods
 * - meta properties
 */

exports._initScope = function () {
  this._initData()
  this._initComputed()
  this._initMethods()
  this._initMeta()
}

/**
 * Initialize the data.
 */

exports._initData = function () {
  // proxy data on instance
  var data = this._data
  var keys = Object.keys(data)
  var i = keys.length
  var key
  while (i--) {
    key = keys[i]
    if (!_.isReserved(key)) {
      this._proxy(key)
    }
  }
  // observe data
  Observer.create(data).addVm(this)
}

/**
 * Swap the isntance's $data. Called in $data's setter.
 *
 * @param {Object} newData
 */

exports._setData = function (newData) {
  newData = newData || {}
  var oldData = this._data
  this._data = newData
  var keys, key, i
  // unproxy keys not present in new data
  keys = Object.keys(oldData)
  i = keys.length
  while (i--) {
    key = keys[i]
    if (!_.isReserved(key) && !(key in newData)) {
      this._unproxy(key)
    }
  }
  // proxy keys not already proxied,
  // and trigger change for changed values
  keys = Object.keys(newData)
  i = keys.length
  while (i--) {
    key = keys[i]
    if (!this.hasOwnProperty(key) && !_.isReserved(key)) {
      // new property
      this._proxy(key)
    }
  }
  oldData.__ob__.removeVm(this)
  Observer.create(newData).addVm(this)
  this._digest()
}

/**
 * Proxy a property, so that
 * vm.prop === vm._data.prop
 *
 * @param {String} key
 */

exports._proxy = function (key) {
  // need to store ref to self here
  // because these getter/setters might
  // be called by child instances!
  var self = this
  Object.defineProperty(self, key, {
    configurable: true,
    enumerable: true,
    get: function proxyGetter () {
      return self._data[key]
    },
    set: function proxySetter (val) {
      self._data[key] = val
    }
  })
}

/**
 * Unproxy a property.
 *
 * @param {String} key
 */

exports._unproxy = function (key) {
  delete this[key]
}

/**
 * Force update on every watcher in scope.
 */

exports._digest = function () {
  var i = this._watcherList.length
  while (i--) {
    this._watcherList[i].update()
  }
  var children = this._children
  var child
  if (children) {
    i = children.length
    while (i--) {
      child = children[i]
      if (child.$options.inherit) {
        child._digest()
      }
    }
  }
}

/**
 * Setup computed properties. They are essentially
 * special getter/setters
 */

function noop () {}
exports._initComputed = function () {
  var computed = this.$options.computed
  if (computed) {
    for (var key in computed) {
      var userDef = computed[key]
      var def = {
        enumerable: true,
        configurable: true
      }
      if (typeof userDef === 'function') {
        def.get = _.bind(userDef, this)
        def.set = noop
      } else {
        def.get = userDef.get
          ? _.bind(userDef.get, this)
          : noop
        def.set = userDef.set
          ? _.bind(userDef.set, this)
          : noop
      }
      Object.defineProperty(this, key, def)
    }
  }
}

/**
 * Setup instance methods. Methods must be bound to the
 * instance since they might be called by children
 * inheriting them.
 */

exports._initMethods = function () {
  var methods = this.$options.methods
  if (methods) {
    for (var key in methods) {
      this[key] = _.bind(methods[key], this)
    }
  }
}

/**
 * Initialize meta information like $index, $key & $value.
 */

exports._initMeta = function () {
  var metas = this.$options._meta
  if (metas) {
    for (var key in metas) {
      this._defineMeta(key, metas[key])
    }
  }
}

/**
 * Define a meta property, e.g $index, $key, $value
 * which only exists on the vm instance but not in $data.
 *
 * @param {String} key
 * @param {*} value
 */

exports._defineMeta = function (key, value) {
  var binding = new Binding()
  Object.defineProperty(this, key, {
    enumerable: true,
    configurable: true,
    get: function metaGetter () {
      if (Observer.target) {
        Observer.target.addDep(binding)
      }
      return value
    },
    set: function metaSetter (val) {
      if (val !== value) {
        value = val
        binding.notify()
      }
    }
  })
}<|endoftext|>


<commit_before>class BpmCounter {
  constructor() {
    this.numTaps = 0;
    this.bpm = 0;
    this.lastTappedTime = new Date();
  }

  restart() {
    this.numTaps = 0;
    this.bpm = 0;
    this.lastTappedTime = new Date();
  }

  tick() {
    this.numTaps++;

    let currentTime = new Date();

    let timeDifferenceInMS = currentTime - this.lastTappedTime;

    this.bpm = this.numTaps / (timeDifferenceInMS / 1000);
  }
}
<commit_msg>Fix bug where the BPM calculated was wrong<commit_after>class BpmCounter {
  constructor() {
    this.numTaps = 0;
    this.bpm = 0;
    this.startTapTime = new Date();
  }

  restart() {
    this.numTaps = 0;
    this.bpm = 0;
  }

  tick() {
    if (this.numTaps === 0) {
      this.startTapTime = new Date();
    }

    this.numTaps++;

    let currentTime = new Date();

    let timeDifferenceInMS = currentTime - this.startTapTime;

    this.bpm = this.numTaps / (timeDifferenceInMS / 1000) * 60;
  }
}
<|endoftext|>


<commit_before>Blend.defineClass('Blend.ui.Splitter', {
    extend: 'Blend.ui.Component',
    requires: [
        'Blend.Environment'
    ],
    alias: 'ui.splitter',
    size: 6,
    splitterType: null,
    ghostEl: null,
    element: {
        unselectable: true,
        listeners: {
            mousedown: function () {
                var me = this, handler = me[me.splitterType];
                if (handler) {
                    handler.apply(me, arguments);
                }
            }
        }
    },
    init: function () {
        var me = this, lt;
        me.callParent.apply(me, arguments);
        if (me.parent && me.parent.layout) {
            lt = me.parent.layout.alias.replace('layout.', '');
            if (lt === 'hbox') {
                me.splitterType = 'vertical';
            } else if (lt === 'vbox') {
                me.splitterType = 'horizontal';
            } else {
                throw new Error('Splitter can only be placed in a container component with a HBox or a VBox layout');
            }
        }
        me.element.cls = Blend.cssPrefix(['splitter', 'splitter-' + me.splitterType]);
        me.width = me.height = me.size;
    },
    /**
     * Mousedown on a horizontal splitter
     */
    horizontal: function () {
        var me = this;
        var me = this;
        var interactionHandler = function (evt) {
            Blend.Style.set(me.ghostEl, {
                top: me.checkSetHorizontalPosition(evt.clientY - me.correction.top) - me.halfH,
                left: 0
            });
        };
        var placementHandler = function (evt) {
            me.removeListeners(placementHandler, interactionHandler);
            me.relocateSplitter();
            me.parent.layout.updateLayoutContext({
                top: me.getAComponent(),
                bottom: me.getBComponent(),
                delta: me.relocateSplitter()
            });
        };
        me.setup(placementHandler, interactionHandler);
    },
    /**
     * Relocated the splitter to its new position and removed the ghost splitter
     */
    relocateSplitter: function () {
        var me = this, delta = {}, ghostPos = Blend.Element.getSizeAndPosition(me.ghostEl);
        Blend.Style.set(me.ghostEl, {
            display: 'none'
        });
        if (me.splitterType === 'vertical') {
            delete(ghostPos.height);
        } else {
            delete(ghostPos.width);
        }
        Blend.Style.set(me.element, ghostPos);
        Blend.foreach(me.oldPosition, function (v, k) {
            delta[k] = Math.round(ghostPos[k] - v);
        });
        return delta;
    },
    createGhostSplitter: function () {
        var me = this;
        if (!me.ghostEl) {
            me.ghostEl = Blend.Element.clone(me.element);
            me.ghostEl['background-color'] = 'red';
            me.element.parentNode.appendChild(me.ghostEl);
        }
        Blend.Style.set(me.ghostEl, {
            display: ''
        });
        Blend.Style.set(me.ghostEl, me.oldPosition);
        Blend.CSS.set(me.ghostEl, 'b-splitter-active');
    },
    /**
     * Setup and do common processing for both splitter types
     */
    setup: function (placementHandler, interactionHandler) {
        var me = this;
        me.halfW = (me.width / 2);
        me.halfH = (me.height / 2);
        me.oldPosition = Blend.Element.getSizeAndPosition(me.element);
        /**
         * Since the mouse movement is positioned on the document element, we need
         * to translate mouse position to the internal location of the container
         * where the splitter is a child of
         */
        me.correction = me.parent.getElement().getBoundingClientRect();
        me.setupAdjacent('aCompInfo', me.getAComponent());
        me.setupAdjacent('bCompInfo', me.getBComponent());
        me.createGhostSplitter();
        //Blend.addEventListener(me.ghostEl, 'mouseup', placementHandler);
        Blend.Environment.addEventListener(Blend.getDocument(), 'mouseup', placementHandler);
        Blend.Environment.addEventListener(Blend.getDocument(), 'mousemove', interactionHandler);
    },
    setupAdjacent: function (name, comp) {
        var me = this, info = Blend.Element.getSizeAndPosition(comp.getElement());
        info.minWidth = comp.minWidth || null;
        info.minHeight = comp.minHeight || null;
        me[name] = info;
    },
    removeListeners: function (placementHandler, interactionHandler) {
        var me = this;
        //Blend.removeEventListener(me.ghostEl, 'mouseup', placementHandler);
        Blend.Environment.removeEventListener(Blend.getDocument(), 'mouseup', placementHandler);
        Blend.Environment.removeEventListener(Blend.getDocument(), 'mousemove', interactionHandler);
    },
    /**
     * Check if the new horizontal position can actually be used
     */
    checkSetHorizontalPosition: function (pos) {
        var me = this, min, max;
        // check for minHeight of the top component
        if (me.aCompInfo.minHeight) {
            min = me.aCompInfo.top + me.aCompInfo.minHeight;
        } else {
            min = me.aCompInfo.top;
        }

        // check for minHeight of the right component
        if (me.bCompInfo.minHeight) {
            max = me.bCompInfo.top + (me.bCompInfo.height - me.bCompInfo.minHeight);
        } else {
            max = (me.bCompInfo.top + (me.bCompInfo.height - me.height));
        }

        // check for not passing the top component
        if (pos < min) {
            pos = min + me.halfH;
        }

        // check for not passing the right component
        if (pos > max) {
            pos = max + me.halfH;
        }
        return pos;
    }
});<commit_msg>Added initializer interface so we can have the option to skip having the Splitter code all the time regardless of whether its usage.<commit_after>Blend.defineClass('Blend.ui.Splitter', {
    extend: 'Blend.ui.Component',
    requires: [
        'Blend.Environment',
        'Blend.layout.plugins.Splitter'
    ],
    alias: 'ui.splitter',
    size: 7,
    splitterType: null,
    ghostEl: null,
    flex: false,
    element: {
        unselectable: true,
        listeners: {
            mousedown: function () {
                var me = this, handler = me[me.splitterType];
                if (handler) {
                    handler.apply(me, arguments);
                }
            }
        }
    },
    init: function () {
        var me = this, lt;
        me.callParent.apply(me, arguments);
        if (me.parent && me.parent.layout) {
            lt = me.parent.layout.alias.replace('layout.', '');
            if (lt === 'hbox') {
                me.splitterType = 'vertical';
            } else if (lt === 'vbox') {
                me.splitterType = 'horizontal';
            } else {
                throw new Error('Splitter can only be placed in a container component with a HBox or a VBox layout');
            }
        }
        me.element.cls = Blend.cssPrefix(['splitter', 'splitter-' + me.splitterType]);
        me.width = me.height = me.size;
    },
    /**
     * Mousedown on a horizontal splitter
     */
    horizontal: function () {
        var me = this;
        var me = this;
        var interactionHandler = function (evt) {
            Blend.Style.set(me.ghostEl, {
                top: me.checkSetHorizontalPosition(evt.clientY - me.correction.top) - me.halfH,
                left: 0
            });
        };
        var placementHandler = function (evt) {
            me.removeListeners(placementHandler, interactionHandler);
            me.relocateSplitter();
            me.parent.layout.updateLayoutContext({
                top: me.getAComponent(),
                bottom: me.getBComponent(),
                delta: me.relocateSplitter()
            });
        };
        me.setup(placementHandler, interactionHandler);
    },
    /**
     * Relocated the splitter to its new position and removed the ghost splitter
     */
    relocateSplitter: function () {
        var me = this, delta = {}, ghostPos = Blend.Element.getSizeAndPosition(me.ghostEl);
        Blend.Style.set(me.ghostEl, {
            display: 'none'
        });
        if (me.splitterType === 'vertical') {
            delete(ghostPos.height);
        } else {
            delete(ghostPos.width);
        }
        Blend.Style.set(me.element, ghostPos);
        Blend.foreach(me.oldPosition, function (v, k) {
            delta[k] = Math.round(ghostPos[k] - v);
        });
        return delta;
    },
    createGhostSplitter: function () {
        var me = this;
        if (!me.ghostEl) {
            me.ghostEl = Blend.Element.clone(me.element);
            me.ghostEl['background-color'] = 'red';
            me.element.parentNode.appendChild(me.ghostEl);
        }
        Blend.Style.set(me.ghostEl, {
            display: ''
        });
        Blend.Style.set(me.ghostEl, me.oldPosition);
        Blend.CSS.set(me.ghostEl, 'b-splitter-active');
    },
    /**
     * Setup and do common processing for both splitter types
     */
    setup: function (placementHandler, interactionHandler) {
        var me = this;
        me.halfW = (me.width / 2);
        me.halfH = (me.height / 2);
        me.oldPosition = Blend.Element.getSizeAndPosition(me.element);
        /**
         * Since the mouse movement is positioned on the document element, we need
         * to translate mouse position to the internal location of the container
         * where the splitter is a child of
         */
        me.correction = me.parent.getElement().getBoundingClientRect();
        me.setupAdjacent('aCompInfo', me.getAComponent());
        me.setupAdjacent('bCompInfo', me.getBComponent());
        me.createGhostSplitter();
        //Blend.addEventListener(me.ghostEl, 'mouseup', placementHandler);
        Blend.Environment.addEventListener(Blend.getDocument(), 'mouseup', placementHandler);
        Blend.Environment.addEventListener(Blend.getDocument(), 'mousemove', interactionHandler);
    },
    setupAdjacent: function (name, comp) {
        var me = this, info = Blend.Element.getSizeAndPosition(comp.getElement());
        info.minWidth = comp.minWidth || null;
        info.minHeight = comp.minHeight || null;
        me[name] = info;
    },
    removeListeners: function (placementHandler, interactionHandler) {
        var me = this;
        //Blend.removeEventListener(me.ghostEl, 'mouseup', placementHandler);
        Blend.Environment.removeEventListener(Blend.getDocument(), 'mouseup', placementHandler);
        Blend.Environment.removeEventListener(Blend.getDocument(), 'mousemove', interactionHandler);
    },
    /**
     * Check if the new horizontal position can actually be used
     */
    checkSetHorizontalPosition: function (pos) {
        var me = this, min, max;
        // check for minHeight of the top component
        if (me.aCompInfo.minHeight) {
            min = me.aCompInfo.top + me.aCompInfo.minHeight;
        } else {
            min = me.aCompInfo.top;
        }

        // check for minHeight of the right component
        if (me.bCompInfo.minHeight) {
            max = me.bCompInfo.top + (me.bCompInfo.height - me.bCompInfo.minHeight);
        } else {
            max = (me.bCompInfo.top + (me.bCompInfo.height - me.height));
        }

        // check for not passing the top component
        if (pos < min) {
            pos = min + me.halfH;
        }

        // check for not passing the right component
        if (pos > max) {
            pos = max + me.halfH;
        }
        return pos;
    },
    statics: {
        initialize: function (layout) {
            layout._splitter = Blend.create('Blend.layout.plugins.Splitter', {
                layout: layout
            });
        }
    }
});<|endoftext|>


<commit_before>import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3-color';
import scale from 'd3-scale';
import R from 'ramda';
import chroma from 'chroma-js';

import ms from './modules/ms';

window.d3 = d3;
window.scale = scale;
window.R = R;
window.chroma = chroma;

// var App = props => (
//

//     Hello
//

// );

const w = 300;
const h = 300;
const layers = 30;

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}

let App = React.createClass({
  getInitialState () {
    return {
      rotation: 0,
      angle: 0
    }
  },
  render () {
    return (

 this.setState({rotation: 360 - cursorX/window.innerWidth * 360, angle: 180 - cursorY/window.innerHeight * 180})} style={{
        // overflow:'scroll',
        width: '100%',
        height: '100%',
        // background: '#000',
        // display: 'flex',
        // flexDirection: 'column',
        // alignItems: 'center',
        // justifyContent: 'center'
      }}>
        <div style={{
          position: 'absolute',
          top: '50%',
          // left: '50%',
          transformStyle: 'preserve-3d',
          position: 'relative',
          transform: `translateX(0%) rotateX(${this.state.angle}deg) rotateZ(${this.state.rotation}deg)`,
          // perspective: '1000px',
          // perspectiveOrigin: '0% 50%',
        }}>
          {
            R.range(0, layers).map(layer =>
              <canvas
                key={layer}
                id={`canvas${layer}`}
                width={w}
                height={h}
                style={{
                  // background: 'red',
                  top: '50%',
                  left: '50%',
                  display: 'block',
                  position: 'absolute',
                  transform: `translateX(-50%) translateY(-50%) translateZ(${(layer - layers/2)*20 }px) scale(1)`,
                }}
              />
            )
          }

    );
  }
});

// l in lab color
let layerToL = scale.linear().range([0, 150]).domain([layers, 0]);
// a in lab color
let xToA = scale.linear().range([-100, 100]).domain([0, w]);
// b in lab color
let yToB = scale.linear().range([-100, 100]).domain([0, h]);

// x in xyz color
let layerToZ = scale.linear().range([0, 150]).domain([layers, 0]);
// a in xyz color
let xToX = scale.linear().range([0, 1]).domain([0, w]);
// b in xyz color
let yToY = scale.linear().range([0, 1]).domain([0, h]);

function render () {
  ReactDOM.render(<App />, document.getElementById('root'));

  for (var layer = 0; layer < layers; layer++) {
    var canvas = document.getElementById(`canvas${layer}`);
    if (canvas.getContext) {
      var ctx = canvas.getContext('2d');
      // debugger;
      var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
      var data = imageData.data;

      // setTimeout(() => {
        var i = 0;
        for (var y = 0; y < h; y++) {
          for (var x = 0; x < w; x++) {
            var color = d3.lab(layerToL(layer), xToA(x), yToB(y)).rgb();
            if (color.displayable()) {
              data[0 + i * 4] = color.r;
              data[1 + i * 4] = color.g;
              data[2 + i * 4] = color.b;
              data[3 + i * 4] = 255;
            }
            i++;
          }
        }
        ctx.putImageData(imageData, 0, 0);
      // }, 0);
    }
  }
}

render();
// window.onresize = render;
<commit_msg>Add better stuff<commit_after>import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3-color';
import scale from 'd3-scale';
import R from 'ramda';
import chroma from 'chroma-js';

import ms from './modules/ms';

window.d3 = d3;
window.scale = scale;
window.R = R;
window.chroma = chroma;

const w = 300;
const h = 300;
const layers = 25;

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}

let App = React.createClass({
  getInitialState () {
    return {
      rotation: 0,
      angle: 0
    }
  },
  render () {
    return (

 this.setState({rotation: 360 - cursorX/window.innerWidth * 360, angle: 180 - cursorY/window.innerHeight * 180})} style={{
        // overflow:'scroll',
        width: '100%',
        height: '100%',
        perspective: '1000px',
        // background: '#000',
        // display: 'flex',
        // flexDirection: 'column',
        // alignItems: 'center',
        // justifyContent: 'center'
      }}>
        <div style={{
          position: 'absolute',
          top: '50%',
          // left: '50%',
          transformStyle: 'preserve-3d',
          position: 'relative',
          transform: `translateX(0%) rotateX(${this.state.angle}deg) rotateZ(${this.state.rotation}deg)`,
          // perspectiveOrigin: '0% 50%',
        }}>
          {
            R.range(0, layers).map(layer =>
              <canvas
                key={layer}
                id={`canvas${layer}`}
                width={w}
                height={h}
                style={{
                  // background: 'red',
                  top: '50%',
                  left: '50%',
                  display: 'block',
                  position: 'absolute',
                  transform: `translateX(-50%) translateY(-50%) translateZ(${(layer - layers/2)*20 }px) scale(1.5)`,
                }}
              />
            )
          }

    );
  }
});

// l in lab color
let layerToL = scale.linear().range([0, 150]).domain([layers, 0]);
// a in lab color
let xToA = scale.linear().range([-100, 100]).domain([0, w]);
// b in lab color
let yToB = scale.linear().range([-100, 100]).domain([0, h]);

// l in hcl color
// let layerToL = scale.linear().range([0, 150]).domain([layers, 0]);
// c in hcl color
let xToC = scale.linear().range([0, 150]).domain([0, w]);
// h in hcl color
let yToH = scale.linear().range([0, 360]).domain([0, h]);

function xyToRadiusAngle (x, y) {
  let radius = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  let angle = Math.atan2(y, x);
  return { radius, angle };
}

function render () {
  ReactDOM.render(<App />, document.getElementById('root'));

  for (var layer = 0; layer < layers; layer++) {
    var canvas = document.getElementById(`canvas${layer}`);
    if (canvas.getContext) {
      var ctx = canvas.getContext('2d');
      // debugger;
      var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
      var data = imageData.data;

      // setTimeout(() => {
        var i = 0;
        for (var y = 0; y < h; y++) {
          for (var x = 0; x < w; x++) {
            let {radius, angle} = xyToRadiusAngle(x - w / 2, y - h / 2);
            let angleDegrees = angle * (180 / Math.PI) + 180; // Add 180 so range is between 0 and 360, though it works without it
            // let color = {r: 0, g: 0, b: 0};
            // if (radius < 100) {
            //   color = {r: 255, g: 0, b: 0};
            // }
            // let color = d3.hcl(yToH(y), xToC(x), layerToL(layer)).rgb();
            let color = d3.hcl(angleDegrees, radius * 0.7, layerToL(layer)).rgb();
            // let color = d3.lab(layerToL(layer), xToA(x), yToB(y)).rgb();
            // let color2 = d3.lab(layerToL(layer), xToA(x), yToB(y)).rgb();
            data[0 + i * 4] = color.r;
            data[1 + i * 4] = color.g;
            data[2 + i * 4] = color.b;
            // data[3 + i * 4] = color.displayable() ? 255 : 2;
            data[3 + i * 4] = (color.displayable() && (angleDegrees > 45)) ? 255 : 2;
            // data[3 + i * 4] = color.displayable() ? 255 : (color2.displayable() ? 20 : 0);
            i++;
          }
        }
        ctx.putImageData(imageData, 0, 0);
      // }, 0);
    }
  }
}

render();
// window.onresize = render;
<|endoftext|>