<commit_before>import * as I from 'immutable';

import { rationalMatrixMethods, rationalMatrices } from '../arithmetic/types';

class VectorLabeledEdge {
  constructor(head, tail, shift) {
    this.head = head;
    this.tail = tail;
    this.shift = shift;
  }

  toString() {
    return `VectorLabeledEdge(${this.head}, ${this.tail}, ${this.shift})`;
  }

  reverse() {
    return new VectorLabeledEdge(
      this.tail, this.head, rationalMatrices.negative(this.shift));
  }

  canonical() {
    if (this.tail < this.head
        || (this.tail == this.head && this.shift.find(x => x != 0) < 0)
       )
      return this.reverse();
    else
      return this;
  }

  get __typeName() { return 'VectorLabeledEdge'; }
};

export const ops = rationalMatrixMethods.register({
  __repr__  : {
    VectorLabeledEdge: x => ({
      head: ops.repr(x.head),
      tail: ops.repr(x.tail),
      shift: ops.repr(x.shift)
    })
  },
  __VectorLabeledEdge__: {
    Object: ({ VectorLabeledEdge: obj }) =>
      new VectorLabeledEdge(
        ops.fromRepr(obj.head),
        ops.fromRepr(obj.tail),
        ops.fromRepr(obj.shift))
  }
}).ops();

const Graph = I.Record({
  dim  : undefined,
  edges: undefined
});

Graph.prototype.toString = function toString() {
  return 'PGraph('+this.edges+')';
};

const encode = value => I.fromJS(ops.repr(value));
const decode = value => ops.fromRepr(value.toJS());

export function make(data) {
  const edges = I.Set(data)
    .map(([h, t, s]) => new VectorLabeledEdge(h, t, s).canonical());
  if (edges.size == 0)
    throw new Error('cannot be empty');

  const dim = edges.first().shift.length;
  if (edges.some(e => e.shift.length != dim))
    throw new Error('must have consistent shift dimensions');

  return new Graph({ dim: dim, edges: edges });
};

export function adjacencies(graph) {
  const target = e => ({ v: e.tail, s: e.shift });

  let res = I.Map();
  for (const e of graph.edges) {
    res = res
      .update(e.head, a => (a || I.List()).push(target(e)))
      .update(e.tail, a => (a || I.List()).push(target(e.reverse())));
  }
  return res;
};

export function coordinationSeq(graph, start, dist) {
  const adj  = adjacencies(graph);
  const zero = ops.vector(graph.dim);

  let oldShell = I.Set();
  let thisShell = I.Set([I.fromJS([start, zero])]);
  const res = [1];

  for (const i of I.Range(1, dist+1)) {
    let nextShell = I.Set().asMutable();
    for (const item of thisShell) {
      const [v, s] = item.toJS();
      for (const { v: w, s: t } of adj.get(v)) {
        const key = I.fromJS([w, ops.plus(s, t)]);
        if (!oldShell.contains(key) && !thisShell.contains(key))
          nextShell.add(key);
      }
    }

    res.push(nextShell.size);
    oldShell = thisShell;
    thisShell = nextShell;
  }

  return res;
};

const _componentInOrbitGraph = (graph, start) => {
  const adj = adjacencies(graph);
  const queue = [start]
  const bridges = [];
  const nodeShifts = I.Map([[start, ops.vector(graph.dim)]]).asMutable();

  while (queue.length) {
    const v = queue.shift();
    const av = nodeShifts.get(v);

    for (const {v: w, s: shift} of adj.get(v)) {
      if (nodeShifts.get(w) == undefined) {
        queue.push(w);
        nodeShifts.set(w, ops.minus(av, shift));
      }
      else {
        const aw = nodeShifts.get(w);
        const newShift = ops.plus(shift, ops.minus(aw, av));
        const pivot = newShift.find(x => ops.ne(x, 0));

        if (pivot != undefined && ops.gt(pivot, 0))
          bridges.push({ v, w, s: newShift });
      }
    }
  }

  return {
    nodes: I.Set(nodeShifts.keys()),
    nodeShifts,
    bridges
  };
};

const _isConnectedOrbitGraph = (graph) => {
  const verts = I.List(adjacencies(graph).keySeq());
  const comp = _componentInOrbitGraph(graph, verts.first());

  return comp.nodes.size >= verts.size;
};

const _basis = M => {
  const T = ops.triangulation(M).R;
  return T.slice(0, ops.rank(T));
};

const _componentInCoverGraph = (graph, start) => {
  const { nodes, nodeShifts, bridges } = _componentInOrbitGraph(graph, start);
  const basis = _basis(bridges.map(b => b.s));
  const transform = ops.inverse(basis);
  const old2new = I.Map(I.List(nodes).zip(I.Range(1, nodes.size+1)));

  const newEdges = graph.edges
    .filter(({ head, tail }) =>
            old2new.get(head) != null && old2new.get(tail) != null)
    .map(({ head, tail, shift }) => {
      const [v, w] = [old2new.get(head), old2new.get(tail)];
      const [av, aw] = [nodeShifts.get(head), nodeShifts.get(tail)];
      const t = ops.times(ops.plus(shift, ops.minus(aw, av)), transform);
      return [v, w, t];
    });

  return {
    basis,
    nodes: nodes.toArray(),
    multiplicity: ops.determinant(basis),
    graph: make(newEdges)
  };
};

export function isConnected(graph) {
  const verts = I.List(adjacencies(graph).keySeq());
  const comp = _componentInCoverGraph(graph, verts.first());

  return comp.nodes.length >= verts.size && comp.multiplicity == 1;
};

export function connectedComponents(graph) {
  const verts = I.List(adjacencies(graph).keySeq());
  const seen = I.Set().asMutable();
  const result = [];

  for (const start of verts) {
    if (!seen.contains(start)) {
      const comp = _componentInCoverGraph(graph, start);
      result.push(comp);
      comp.nodes.forEach(v => seen.add(v));
    }
  }

  return result;
};

export function barycentricPlacement(graph) {
  if (!isConnected(graph))
    throw new Error('must have a connected orbit graph');

  const adj   = adjacencies(graph);
  const verts = I.List(adj.keySeq());
  const vIdcs = I.Map(I.Range(0, verts.size).map(i => [verts.get(i), i]));

  const n = verts.size;
  const d = graph.dim;
  let A = ops.matrix(n+1, n);
  let t = ops.matrix(n+1, d);

  verts.forEach((v, i) => {
    adj.get(v).forEach(c => {
      if (c.v != v) {
        const j = vIdcs.get(c.v);
        A[i][j] -= 1;
        A[i][i] += 1;
        t[i] = ops.plus(t[i], c.s);
      }
    });
  });
  A[n][0] = 1;

  const p = ops.solve(A, t);

  return I.Map(I.Range(0, n).map(i => [verts.get(i), p[i]]));
};

export function barycentricPlacementAsFloat(graph) {
  return barycentricPlacement(graph).map(p => p.map(x => ops.toJS(x)));
};

export function isStable(graph, pos=barycentricPlacement(graph)) {
  const verts = I.List(adjacencies(graph).keySeq());
  const seen = I.Set().asMutable();

  for (const v of verts) {
    const p = pos.get(v);
    const key = encode(p.map(x => ops.mod(x, 1)));
    if (seen.contains(key))
      return false;
    else
      seen.add(key);
  }

  return true;
};

export function isLocallyStable(graph, pos=barycentricPlacement(graph)) {
  const adj = adjacencies(graph);
  const verts = I.List(adj.keySeq());

  for (const v of verts) {
    const seen = I.Set().asMutable();

    for (const w of adj.get(v)) {
      const p = ops.plus(pos.get(w.v), w.s);
      const key = encode(p);
      if (seen.contains(key))
        return false;
      else
        seen.add(key);
    }
  }

  return true;
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const test = function test(g) {
    console.log('g = '+g);
    console.log('  cs  = '+coordinationSeq(g, 1, 10));
    if (isConnected(g)) {
      console.log('  pos = '+barycentricPlacement(g));
      console.log('      = '+barycentricPlacementAsFloat(g));
      console.log('  stable: '+isStable(g));
      console.log('  locally stable: '+isLocallyStable(g));
    }

    for (const comp of connectedComponents(g)) {
      console.log('  component:');
      console.log('    nodes = '+comp.nodes);
      console.log('    graph = '+comp.graph);
      console.log('    basis = '+comp.basis);
      console.log('    multiplicity = '+comp.multiplicity);
    }
    console.log();
  };

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ],
              [ 1, 4, [ 0, 0 ] ],
              [ 1, 4, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ -1,  1,  1 ] ],
              [ 1, 1, [  0, -1,  1 ] ],
              [ 1, 1, [  0,  0, -1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 0 ] ],
              [ 1, 2, [ 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 2, 0, 0 ] ],
              [ 1, 2, [ 0, 2, 0 ] ],
              [ 1, 2, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 3, [ 0, 0, 0 ] ],
              [ 1, 3, [ 2, 0, 0 ] ],
              [ 1, 3, [ 0, 2, 0 ] ],
              [ 1, 3, [ 0, 0, 2 ] ],
              [ 2, 4, [ 0, 0, 0 ] ],
              [ 2, 4, [ 2, 0, 0 ] ],
              [ 2, 4, [ 0, 2, 0 ] ],
              [ 2, 4, [ 0, 0, 2 ] ] ]));
}
<commit_msg>add a convenience function for creating an edge<commit_after>import * as I from 'immutable';

import { rationalMatrixMethods, rationalMatrices } from '../arithmetic/types';

class VectorLabeledEdge {
  constructor(head, tail, shift) {
    this.head = head;
    this.tail = tail;
    this.shift = shift;
  }

  toString() {
    return `VectorLabeledEdge(${this.head}, ${this.tail}, ${this.shift})`;
  }

  reverse() {
    return new VectorLabeledEdge(
      this.tail, this.head, rationalMatrices.negative(this.shift));
  }

  canonical() {
    if (this.tail < this.head
        || (this.tail == this.head && this.shift.find(x => x != 0) < 0)
       )
      return this.reverse();
    else
      return this;
  }

  get __typeName() { return 'VectorLabeledEdge'; }
};

export const ops = rationalMatrixMethods.register({
  __repr__  : {
    VectorLabeledEdge: x => ({
      head: ops.repr(x.head),
      tail: ops.repr(x.tail),
      shift: ops.repr(x.shift)
    })
  },
  __VectorLabeledEdge__: {
    Object: ({ VectorLabeledEdge: obj }) =>
      new VectorLabeledEdge(
        ops.fromRepr(obj.head),
        ops.fromRepr(obj.tail),
        ops.fromRepr(obj.shift))
  }
}).ops();

const Graph = I.Record({
  dim  : undefined,
  edges: undefined
});

Graph.prototype.toString = function toString() {
  return 'PGraph('+this.edges+')';
};

const encode = value => I.fromJS(ops.repr(value));
const decode = value => ops.fromRepr(value.toJS());

export function makeEdge(head, tail, shift) {
  return new VectorLabeledEdge(head, tail, shift);
};

export function make(data) {
  const edges = I.Set(data)
    .map(([h, t, s]) => makeEdge(h, t, s).canonical());
  if (edges.size == 0)
    throw new Error('cannot be empty');

  const dim = edges.first().shift.length;
  if (edges.some(e => e.shift.length != dim))
    throw new Error('must have consistent shift dimensions');

  return new Graph({ dim: dim, edges: edges });
};

export function adjacencies(graph) {
  const target = e => ({ v: e.tail, s: e.shift });

  let res = I.Map();
  for (const e of graph.edges) {
    res = res
      .update(e.head, a => (a || I.List()).push(target(e)))
      .update(e.tail, a => (a || I.List()).push(target(e.reverse())));
  }
  return res;
};

export function coordinationSeq(graph, start, dist) {
  const adj  = adjacencies(graph);
  const zero = ops.vector(graph.dim);

  let oldShell = I.Set();
  let thisShell = I.Set([I.fromJS([start, zero])]);
  const res = [1];

  for (const i of I.Range(1, dist+1)) {
    let nextShell = I.Set().asMutable();
    for (const item of thisShell) {
      const [v, s] = item.toJS();
      for (const { v: w, s: t } of adj.get(v)) {
        const key = I.fromJS([w, ops.plus(s, t)]);
        if (!oldShell.contains(key) && !thisShell.contains(key))
          nextShell.add(key);
      }
    }

    res.push(nextShell.size);
    oldShell = thisShell;
    thisShell = nextShell;
  }

  return res;
};

const _componentInOrbitGraph = (graph, start) => {
  const adj = adjacencies(graph);
  const queue = [start]
  const bridges = [];
  const nodeShifts = I.Map([[start, ops.vector(graph.dim)]]).asMutable();

  while (queue.length) {
    const v = queue.shift();
    const av = nodeShifts.get(v);

    for (const {v: w, s: shift} of adj.get(v)) {
      if (nodeShifts.get(w) == undefined) {
        queue.push(w);
        nodeShifts.set(w, ops.minus(av, shift));
      }
      else {
        const aw = nodeShifts.get(w);
        const newShift = ops.plus(shift, ops.minus(aw, av));
        const pivot = newShift.find(x => ops.ne(x, 0));

        if (pivot != undefined && ops.gt(pivot, 0))
          bridges.push({ v, w, s: newShift });
      }
    }
  }

  return {
    nodes: I.Set(nodeShifts.keys()),
    nodeShifts,
    bridges
  };
};

const _isConnectedOrbitGraph = (graph) => {
  const verts = I.List(adjacencies(graph).keySeq());
  const comp = _componentInOrbitGraph(graph, verts.first());

  return comp.nodes.size >= verts.size;
};

const _basis = M => {
  const T = ops.triangulation(M).R;
  return T.slice(0, ops.rank(T));
};

const _componentInCoverGraph = (graph, start) => {
  const { nodes, nodeShifts, bridges } = _componentInOrbitGraph(graph, start);
  const basis = _basis(bridges.map(b => b.s));
  const transform = ops.inverse(basis);
  const old2new = I.Map(I.List(nodes).zip(I.Range(1, nodes.size+1)));

  const newEdges = graph.edges
    .filter(({ head, tail }) =>
            old2new.get(head) != null && old2new.get(tail) != null)
    .map(({ head, tail, shift }) => {
      const [v, w] = [old2new.get(head), old2new.get(tail)];
      const [av, aw] = [nodeShifts.get(head), nodeShifts.get(tail)];
      const t = ops.times(ops.plus(shift, ops.minus(aw, av)), transform);
      return [v, w, t];
    });

  return {
    basis,
    nodes: nodes.toArray(),
    multiplicity: ops.determinant(basis),
    graph: make(newEdges)
  };
};

export function isConnected(graph) {
  const verts = I.List(adjacencies(graph).keySeq());
  const comp = _componentInCoverGraph(graph, verts.first());

  return comp.nodes.length >= verts.size && comp.multiplicity == 1;
};

export function connectedComponents(graph) {
  const verts = I.List(adjacencies(graph).keySeq());
  const seen = I.Set().asMutable();
  const result = [];

  for (const start of verts) {
    if (!seen.contains(start)) {
      const comp = _componentInCoverGraph(graph, start);
      result.push(comp);
      comp.nodes.forEach(v => seen.add(v));
    }
  }

  return result;
};

export function barycentricPlacement(graph) {
  if (!isConnected(graph))
    throw new Error('must have a connected orbit graph');

  const adj   = adjacencies(graph);
  const verts = I.List(adj.keySeq());
  const vIdcs = I.Map(I.Range(0, verts.size).map(i => [verts.get(i), i]));

  const n = verts.size;
  const d = graph.dim;
  let A = ops.matrix(n+1, n);
  let t = ops.matrix(n+1, d);

  verts.forEach((v, i) => {
    adj.get(v).forEach(c => {
      if (c.v != v) {
        const j = vIdcs.get(c.v);
        A[i][j] -= 1;
        A[i][i] += 1;
        t[i] = ops.plus(t[i], c.s);
      }
    });
  });
  A[n][0] = 1;

  const p = ops.solve(A, t);

  return I.Map(I.Range(0, n).map(i => [verts.get(i), p[i]]));
};

export function barycentricPlacementAsFloat(graph) {
  return barycentricPlacement(graph).map(p => p.map(x => ops.toJS(x)));
};

export function isStable(graph, pos=barycentricPlacement(graph)) {
  const verts = I.List(adjacencies(graph).keySeq());
  const seen = I.Set().asMutable();

  for (const v of verts) {
    const p = pos.get(v);
    const key = encode(p.map(x => ops.mod(x, 1)));
    if (seen.contains(key))
      return false;
    else
      seen.add(key);
  }

  return true;
};

export function isLocallyStable(graph, pos=barycentricPlacement(graph)) {
  const adj = adjacencies(graph);
  const verts = I.List(adj.keySeq());

  for (const v of verts) {
    const seen = I.Set().asMutable();

    for (const w of adj.get(v)) {
      const p = ops.plus(pos.get(w.v), w.s);
      const key = encode(p);
      if (seen.contains(key))
        return false;
      else
        seen.add(key);
    }
  }

  return true;
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const test = function test(g) {
    console.log('g = '+g);
    console.log('  cs  = '+coordinationSeq(g, 1, 10));
    if (isConnected(g)) {
      console.log('  pos = '+barycentricPlacement(g));
      console.log('      = '+barycentricPlacementAsFloat(g));
      console.log('  stable: '+isStable(g));
      console.log('  locally stable: '+isLocallyStable(g));
    }

    for (const comp of connectedComponents(g)) {
      console.log('  component:');
      console.log('    nodes = '+comp.nodes);
      console.log('    graph = '+comp.graph);
      console.log('    basis = '+comp.basis);
      console.log('    multiplicity = '+comp.multiplicity);
    }
    console.log();
  };

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ],
              [ 1, 4, [ 0, 0 ] ],
              [ 1, 4, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ -1,  1,  1 ] ],
              [ 1, 1, [  0, -1,  1 ] ],
              [ 1, 1, [  0,  0, -1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 0 ] ],
              [ 1, 2, [ 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 2, 0, 0 ] ],
              [ 1, 2, [ 0, 2, 0 ] ],
              [ 1, 2, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 3, [ 0, 0, 0 ] ],
              [ 1, 3, [ 2, 0, 0 ] ],
              [ 1, 3, [ 0, 2, 0 ] ],
              [ 1, 3, [ 0, 0, 2 ] ],
              [ 2, 4, [ 0, 0, 0 ] ],
              [ 2, 4, [ 2, 0, 0 ] ],
              [ 2, 4, [ 0, 2, 0 ] ],
              [ 2, 4, [ 0, 0, 2 ] ] ]));
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

require('jest');
require('whatwg-fetch');
require('mock-local-storage');

window.localStorage = global.localStorage;
window.$ = window.jQuery = require('jquery');
window._ = require('lodash');
window.Backbone = require('backbone');

// URL.createObjectURL() and Worker are referenced by brace so we add mock objects to prevent
// long warning messages from being printed while running the tests.
if (!window.URL) {
  window.URL = {};
}
if (!window.URL.createObjectURL) {
  window.URL.createObjectURL = function() {
    return 'http://localhost';
  };
}
window.Worker = function FakeWorker() {
  this.postMessage = function () { };
  this.onmessage = undefined;
};

window.alert = () => {};

// Setup enzyme's react adapter
const Enzyme = require('enzyme');
const EnzymeAdapter = require('enzyme-adapter-react-16');
Enzyme.configure({ adapter: new EnzymeAdapter() });
<commit_msg>Fix Node 10 localstorage in tests<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

require('jest');
require('whatwg-fetch');
require('mock-local-storage');

Object.defineProperty(window, 'localStorage', {
  value: global.localStorage,
  configurable:true,
  enumerable:true,
  writable:true
});

window.$ = window.jQuery = require('jquery');
window._ = require('lodash');
window.Backbone = require('backbone');

// URL.createObjectURL() and Worker are referenced by brace so we add mock objects to prevent
// long warning messages from being printed while running the tests.
if (!window.URL) {
  window.URL = {};
}
if (!window.URL.createObjectURL) {
  window.URL.createObjectURL = function() {
    return 'http://localhost';
  };
}
window.Worker = function FakeWorker() {
  this.postMessage = function () { };
  this.onmessage = undefined;
};

window.alert = () => {};

// Setup enzyme's react adapter
const Enzyme = require('enzyme');
const EnzymeAdapter = require('enzyme-adapter-react-16');
Enzyme.configure({ adapter: new EnzymeAdapter() });
<|endoftext|>


<commit_before>
(function(){

    dw.visualization.register('grouped-column-chart', 'raphael-chart', {

        // some config
        _showValueLabels: function() { return true; },

        render: function(el) {
            el = $(el);

            this.setRoot(el);

            var me = this,
                c = me.initCanvas({}),
                dataset = me.dataset,
                chart_width = c.w - c.lpad - c.rpad,
                series_gap = 0.05, // pull from theme
                row_gap = 0.01;

            me.axesDef = me.axes();
            if (!me.axesDef) return;

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row');
            }

            me.checkData();

            me._color_opts = {};

            if (me.get('negative-color', false)) {
                me._color_opts.byValue = function(v) {
                    return me.theme().colors[v < 0 ? 'negative' : 'positive'];
                };
            } else {
                me._color_opts.varyLightness = true;
            }

            me.init();

            // compute maximum x-label height
            var lh = 0,
                barColumns = me.getBarColumns(),
                n = barColumns.length;
            _.each(barColumns, function(column, s) {
                lh = Math.max(lh, me.labelHeight(column.title(), 'series', c.w / (n)));
            });
            c.bpad += lh;

            me.initDimensions();

            // store bar references for updates
            me.__bars = {};
            me.__barLbls = {};
            me.__gridlines = {};
            me.__gridlabels = {};
            me.__series_names = {};

            if (!me.theme().columnChart.cutGridLines) me.horzGrid();

            me.update();

            // enable mouse events
            el.mousemove(_.bind(me.onMouseMove, me));

            if (dataset.numRows() > 1) {
                var items = [],
                    lblFmt = me.chart().columnFormatter(me.axes(true).labels);
                dataset.eachRow(function(r) {
                    items.push({
                        label: lblFmt(me.axes(true).labels.val(r)),
                        color: me.getColor(null, r, { varyLightness: true, key: me.axes(true).labels.val(r) })
                    });
                });
                me.addLegend(items, $('#header', c.root.parent()));
            }
            $('.showOnHover').hide();

            if (me.theme().columnChart.cutGridLines) me.horzGrid();

            me.post_render();
            me.renderingComplete();
        },

        update: function() {
            var me = this,
                c = me.__canvas,
                n = me.axesDef.columns.length;

            // draw bars
            _.each(me.getBarColumns(me.get('sort-values'), me.get('reverse-order')), function(column, s) {
                column.each(function(val, r) {
                    me._color_opts.key = me.axes(true).labels.val(r);
                    var d = me.barDimensions(column, s, r),
                        fill = me.getColor(column, r, me._color_opts),
                        stroke = chroma.color(fill).darken(10).hex(),
                        key = column.name()+'-'+r,
                        bar_attrs = {
                            x: d.x,
                            y: d.y,
                            width: d.w,
                            height: d.h,
                            stroke: stroke,
                            fill: fill
                        };

                    me.__bars[key] = me.__bars[key] || me.registerElement(c.paper.rect().attr(bar_attrs), column.name(), r);
                    if (me.theme().columnChart.barAttrs) {
                        me.__bars[key].attr(me.theme().columnChart.barAttrs);
                    }

                    me.__barLbls[key] = me.__barLbls[key] || me.registerLabel(me.label(0,0,'X', { align: 'center', cl: 'value' }), column.name());
                    me.__barLbls[key].animate({
                        x: d.x + d.w * 0.5,
                        y: d.y + d.h * 0.5,
                        txt: me.formatValue(column.val(r))
                    }, 1000, 'expoInOut');
                    me.__barLbls[key].data('row', r);
                    me.__barLbls[key].hide();

                    me.__bars[key].animate(bar_attrs, me.theme().duration, me.theme().easing).data('strokeCol', stroke);

                    var val_y = val >= 0 ? d.y - 10 : d.y + d.h + 10,
                        lbl_y = val < 0 ? d.y - 10 : d.y + d.h + 5,
                        lblcl = ['series'],
                        lbl_w = c.w / (n+2),
                        valign = val >= 0 ? 'top' : 'bottom',
                        halign = 'center',
                        alwaysShow = (me.chart().hasHighlight() && me.chart().isHighlighted(column.name())) || (d.w > 40);

                    if (me.chart().hasHighlight() && me.chart().isHighlighted(column.name())) {
                        lblcl.push('highlighted');
                    }
                    if (d.bw < 30) {
                        //lblcl.push('rotate90');
                        lbl_y += 5;
                        lbl_w = 100;
                        halign = 'right';
                    }
                    if (d.bw < 20) {
                        lblcl.push('smaller');
                        lbl_w = 90;
                    }
                    // add series label
                    if (!/^X\.\d+$/.test(column.title()) && r === 0) {

                        var la = {
                                x: d.bx + d.bw * 0.5,
                                y: lbl_y,
                                w: lbl_w,
                                align: halign,
                                valign: valign,
                                cl: lblcl.join(' '),
                                rotate: d.bw < 30 ? -90 : 0
                            },
                            sl = me.__series_names[column.name()] = me.__series_names[column.name()] ||
                                me.registerLabel(me.label(la.x, la.y, column.title(), la), column.name());

                        sl.animate(la, me.theme().duration, me.theme().easing);
                    }

                });
            });

            // draw baseline
            var y = c.h - me.__scales.y(0) - c.bpad;
            me.path([['M', c.lpad, y], ['L', c.w - c.rpad, y]], 'axis')
                .attr(me.theme().yAxis);
        },

        getBarColumns: function(sortBars, reverse) {
            return this._getBarColumns(sortBars, reverse);
        },

        // hack to be able to overload in stacked-column-charts.js
        _getBarColumns: function(sortBars, reverse) {
            var me = this,
                columns = _.map(me.axesDef.columns, function(i) { return me.dataset.column(i); });
            if (sortBars) {
                columns.sort(function(a, b) {
                    var aType = a.type(true);
                    return aType.toNum ? aType.toNum(a.val(0)) - aType.toNum(b.val(0)) : a.val() > b.val() ? 1 : a.val() == b.val() ? 0 : -1;
                });
            }
            if (reverse) columns.reverse();
            return columns;
        },

        initDimensions: function(r) {
            //
            var me = this, c = me.__canvas;

            me.__domain = dw.utils.minMax(me.getBarColumns());
            if (me.__domain[0] > 0) me.__domain[0] = 0;
            if (me.__domain[1] < 0) me.__domain[1] = 0;
            me.__scales = {
                y: d3.scale.linear().domain(me.__domain)
            };
            //                                                    v-- substract a few pixel to get space for the legend!
            me.__scales.y.rangeRound([0, c.h - c.bpad - c.tpad - 30]);
        },

        /*
         * computes x,y,w,h for each bar
         */
        barDimensions: function(column, s, r) {
            var me = this,
                sc = me.__scales,
                c = me.__canvas,
                n = me.axesDef.columns.length,
                w, h, x, y, i, cw, bw,
                pad = 0.35,
                vspace = 0.1,
                val = column.val(r);

            if (c.w / n < 30) vspace = 0.05;

            cw = (c.w - c.lpad - c.rpad) * (1 - vspace - vspace);
            bw = cw / (n + (n-1) * pad);
            h = sc.y(val) - sc.y(0);
            w = Math.round(bw / column.length);
            if (h >= 0) {
                y = c.h - c.bpad - sc.y(0) - h;
            } else {
                y = c.h - c.bpad - sc.y(0);
                h *= -1;
            }
            if (val !== 0) h = Math.max(0.5, h);
            x = Math.round((c.w - c.lpad - c.rpad) * vspace + c.lpad + s * (bw + bw * pad));
            return { w: w, h: h, x: x + Math.floor((w+1)*r), y: y, bx: x, bw: bw };
        },

        getDataRowByPoint: function(x, y) {
            return 0;
        },

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        /*
         * renders the horizontal grid
         */
        horzGrid: function() {
            // draw tick marks and labels
            var me = this,
                yscale = me.__scales.y,
                c = me.__canvas,
                domain = me.__domain,
                styles = me.__styles,
                ticks = me.getYTicks(yscale, c.h, true);

            ticks = ticks.filter(function(val, t) {
                return val >= domain[0] && val <= domain[1];
            });

            _.each(ticks, function(val, t) {
                var y = c.h - c.bpad - yscale(val),
                    x = c.lpad, ly = y-10, lbl,
                    txt = me.formatValue(val, t == ticks.length-1, true);
                // c.paper.text(x, y, val).attr(styles.labels).attr({ 'text-anchor': 'end' });
                if (me.theme().columnChart.cutGridLines) ly += 10;

                if (val !== 0) {
                    lbl = me.__gridlabels[val] = me.__gridlabels[val] || me.label(x+2, ly, txt, { align: 'left', cl: 'axis', css: { opacity: 0 } });
                    lbl.animate({ x: x+2, y: ly, css: { opacity: 1 } }, me.theme().duration, me.theme().easing);
                }

                if (me.theme().yTicks) {
                    me.path([['M', c.lpad-25, y], ['L', c.lpad-20,y]], 'tick');
                }
                if (me.theme().horizontalGrid) {
                    var p = 'M' + [c.lpad, y] + 'H' + c.w,
                        l = me.__gridlines[val] = me.__gridlines[val] || me.path(p, 'grid').attr(me.theme().horizontalGrid).attr('opacity', 0);

                    if (val === 0) l.attr(me.theme().xAxis);
                    else if (me.theme().columnChart.cutGridLines) l.attr('stroke', me.theme().colors.background);

                    l.animate({ path: p, opacity: 1 }, me.theme().duration, me.theme().easing);
                    l.toBack();
                }
            });

            _.each(me.__gridlabels, function(lbl, val) {
                if (_.indexOf(ticks, +val) < 0) {
                    lbl.animate({ css: { opacity: 0 } }, me.theme().duration, me.theme().easing);
                }
            });
            _.each(me.__gridlines, function(line, val) {
                if (_.indexOf(ticks, +val) < 0) {
                    line.animate({ opacity: 0 }, me.theme().duration, me.theme().easing);
                }
            });
        },

        /*
         * highlights hovered bars and displays value labels
         */
        hover: function(hoveredSeries) {
            var me = this,
                whitishBg = chroma.color(me.theme().colors.background).lch()[0] > 60;

            // compute fill color, depending on hoveredSeries
            function getFill(col, el) {
                var fill = me.getColor(col, el.data('row'), me._color_opts);
                if (hoveredSeries !== undefined && col.name() == dw.utils.name(hoveredSeries)) {
                    fill = chroma.color(fill).darken(whitishBg ? 15 : -25).hex();
                }
                return fill;
            }

            _.each(me.getBarColumns(), function(column) {

                var fill, stroke;

                // highlight/invert the column title
                _.each(me.__labels[column.name()], function(lbl) {
                    if (hoveredSeries !== undefined && column.name() == dw.utils.name(hoveredSeries)) {
                        lbl.addClass('hover');
                        if (lbl.hasClass('showOnHover')) lbl.show(0.5);
                    } else {
                        lbl.removeClass('hover');
                        if (lbl.hasClass('showOnHover')) lbl.hide(0.5);
                    }
                    if (lbl.hasClass('value')) {
                        lbl.removeClass('hover');
                        fill = getFill(column, lbl);
                        //if (me.invertLabel(fill)) {
                            lbl.addClass('inverted');
                        //}
                    }
                });
                // animate the bar fill & stroke
                 _.each(me.__elements[column.name()], function(el) {
                    fill = getFill(column, el);
                    stroke = chroma.color(fill).darken(10).hex();
                    if (el.attrs.fill != fill || el.attrs.stroke != stroke)
                        el.animate({ fill: fill, stroke: stroke }, 50);
                });
            });

            // show/hide the labels that show values on top of the bars
            _.each(me.__barLbls, function(lbl, key) {
                if (hoveredSeries && lbl.data('key') == dw.utils.name(hoveredSeries)) lbl.show();
                else lbl.hide();
            });
        },

        unhoverSeries: function() {
            this.hoverSeries();
        },

        formatValue: function() {
            var me = this;
            // we're overwriting this function with the actual column formatter
            // when it is first called (lazy evaluation)
            me.formatValue = me.chart().columnFormatter(me.axes(true).columns[0]);
            return me.formatValue.apply(me, arguments);
        },

        post_render: function() {

        },

        checkData: function() {
            return true;
        }
    });

}).call(this);<commit_msg>fixed column chart coloring<commit_after>
(function(){

    dw.visualization.register('grouped-column-chart', 'raphael-chart', {

        // some config
        _showValueLabels: function() { return true; },

        render: function(el) {
            el = $(el);

            this.setRoot(el);

            var me = this,
                c = me.initCanvas({}),
                dataset = me.dataset,
                chart_width = c.w - c.lpad - c.rpad,
                series_gap = 0.05, // pull from theme
                row_gap = 0.01;

            me.axesDef = me.axes();
            if (!me.axesDef) return;

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row');
            }

            me.checkData();

            me._color_opts = {};

            if (me.get('negative-color', false)) {
                me._color_opts.byValue = function(v) {
                    return me.theme().colors[v < 0 ? 'negative' : 'positive'];
                };
            } else {
                me._color_opts.varyLightness = true;
            }

            me.init();

            // compute maximum x-label height
            var lh = 0,
                barColumns = me.getBarColumns(),
                n = barColumns.length;
            _.each(barColumns, function(column, s) {
                lh = Math.max(lh, me.labelHeight(column.title(), 'series', c.w / (n)));
            });
            c.bpad += lh;

            me.initDimensions();

            // store bar references for updates
            me.__bars = {};
            me.__barLbls = {};
            me.__gridlines = {};
            me.__gridlabels = {};
            me.__series_names = {};

            if (!me.theme().columnChart.cutGridLines) me.horzGrid();

            me.update();

            // enable mouse events
            el.mousemove(_.bind(me.onMouseMove, me));

            if (dataset.numRows() > 1) {
                var items = [],
                    lblFmt = me.chart().columnFormatter(me.axes(true).labels);
                dataset.eachRow(function(r) {
                    items.push({
                        label: lblFmt(me.axes(true).labels.val(r)),
                        color: me.getColor(null, r, { varyLightness: true, key: me.axes(true).labels.val(r) })
                    });
                });
                me.addLegend(items, $('#header', c.root.parent()));
            }
            $('.showOnHover').hide();

            if (me.theme().columnChart.cutGridLines) me.horzGrid();

            me.post_render();
            me.renderingComplete();
        },

        update: function() {
            var me = this,
                c = me.__canvas,
                n = me.axesDef.columns.length;

            // draw bars
            _.each(me.getBarColumns(me.get('sort-values'), me.get('reverse-order')), function(column, s) {
                column.each(function(val, r) {
                    me._color_opts.key = me.axes(true).labels.val(r);
                    var d = me.barDimensions(column, s, r),
                        fill = me.getColor(column, r, me._color_opts),
                        stroke = chroma.color(fill).darken(10).hex(),
                        key = column.name()+'-'+r,
                        bar_attrs = {
                            x: d.x,
                            y: d.y,
                            width: d.w,
                            height: d.h,
                            stroke: stroke,
                            fill: fill
                        };

                    me.__bars[key] = me.__bars[key] || me.registerElement(c.paper.rect().attr(bar_attrs), column.name(), r);
                    if (me.theme().columnChart.barAttrs) {
                        me.__bars[key].attr(me.theme().columnChart.barAttrs);
                    }

                    me.__barLbls[key] = me.__barLbls[key] || me.registerLabel(me.label(0,0,'X', { align: 'center', cl: 'value' }), column.name());
                    me.__barLbls[key].animate({
                        x: d.x + d.w * 0.5,
                        y: d.y + d.h * 0.5,
                        txt: me.formatValue(column.val(r))
                    }, 1000, 'expoInOut');
                    me.__barLbls[key].data('row', r);
                    me.__barLbls[key].hide();

                    me.__bars[key].animate(bar_attrs, me.theme().duration, me.theme().easing).data('strokeCol', stroke);

                    var val_y = val >= 0 ? d.y - 10 : d.y + d.h + 10,
                        lbl_y = val < 0 ? d.y - 10 : d.y + d.h + 5,
                        lblcl = ['series'],
                        lbl_w = c.w / (n+2),
                        valign = val >= 0 ? 'top' : 'bottom',
                        halign = 'center',
                        alwaysShow = (me.chart().hasHighlight() && me.chart().isHighlighted(column.name())) || (d.w > 40);

                    if (me.chart().hasHighlight() && me.chart().isHighlighted(column.name())) {
                        lblcl.push('highlighted');
                    }
                    if (d.bw < 30) {
                        //lblcl.push('rotate90');
                        lbl_y += 5;
                        lbl_w = 100;
                        halign = 'right';
                    }
                    if (d.bw < 20) {
                        lblcl.push('smaller');
                        lbl_w = 90;
                    }
                    // add series label
                    if (!/^X\.\d+$/.test(column.title()) && r === 0) {

                        var la = {
                                x: d.bx + d.bw * 0.5,
                                y: lbl_y,
                                w: lbl_w,
                                align: halign,
                                valign: valign,
                                cl: lblcl.join(' '),
                                rotate: d.bw < 30 ? -90 : 0
                            },
                            sl = me.__series_names[column.name()] = me.__series_names[column.name()] ||
                                me.registerLabel(me.label(la.x, la.y, column.title(), la), column.name());

                        sl.animate(la, me.theme().duration, me.theme().easing);
                    }

                });
            });

            // draw baseline
            var y = c.h - me.__scales.y(0) - c.bpad;
            me.path([['M', c.lpad, y], ['L', c.w - c.rpad, y]], 'axis')
                .attr(me.theme().yAxis);
        },

        getBarColumns: function(sortBars, reverse) {
            return this._getBarColumns(sortBars, reverse);
        },

        // hack to be able to overload in stacked-column-charts.js
        _getBarColumns: function(sortBars, reverse) {
            var me = this,
                columns = _.map(me.axesDef.columns, function(i) { return me.dataset.column(i); });
            if (sortBars) {
                columns.sort(function(a, b) {
                    var aType = a.type(true);
                    return aType.toNum ? aType.toNum(a.val(0)) - aType.toNum(b.val(0)) : a.val() > b.val() ? 1 : a.val() == b.val() ? 0 : -1;
                });
            }
            if (reverse) columns.reverse();
            return columns;
        },

        initDimensions: function(r) {
            //
            var me = this, c = me.__canvas;

            me.__domain = dw.utils.minMax(me.getBarColumns());
            if (me.__domain[0] > 0) me.__domain[0] = 0;
            if (me.__domain[1] < 0) me.__domain[1] = 0;
            me.__scales = {
                y: d3.scale.linear().domain(me.__domain)
            };
            //                                                    v-- substract a few pixel to get space for the legend!
            me.__scales.y.rangeRound([0, c.h - c.bpad - c.tpad - 30]);
        },

        /*
         * computes x,y,w,h for each bar
         */
        barDimensions: function(column, s, r) {
            var me = this,
                sc = me.__scales,
                c = me.__canvas,
                n = me.axesDef.columns.length,
                w, h, x, y, i, cw, bw,
                pad = 0.35,
                vspace = 0.1,
                val = column.val(r);

            if (c.w / n < 30) vspace = 0.05;

            cw = (c.w - c.lpad - c.rpad) * (1 - vspace - vspace);
            bw = cw / (n + (n-1) * pad);
            h = sc.y(val) - sc.y(0);
            w = Math.round(bw / column.length);
            if (h >= 0) {
                y = c.h - c.bpad - sc.y(0) - h;
            } else {
                y = c.h - c.bpad - sc.y(0);
                h *= -1;
            }
            if (val !== 0) h = Math.max(0.5, h);
            x = Math.round((c.w - c.lpad - c.rpad) * vspace + c.lpad + s * (bw + bw * pad));
            return { w: w, h: h, x: x + Math.floor((w+1)*r), y: y, bx: x, bw: bw };
        },

        getDataRowByPoint: function(x, y) {
            return 0;
        },

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        /*
         * renders the horizontal grid
         */
        horzGrid: function() {
            // draw tick marks and labels
            var me = this,
                yscale = me.__scales.y,
                c = me.__canvas,
                domain = me.__domain,
                styles = me.__styles,
                ticks = me.getYTicks(yscale, c.h, true);

            ticks = ticks.filter(function(val, t) {
                return val >= domain[0] && val <= domain[1];
            });

            _.each(ticks, function(val, t) {
                var y = c.h - c.bpad - yscale(val),
                    x = c.lpad, ly = y-10, lbl,
                    txt = me.formatValue(val, t == ticks.length-1, true);
                // c.paper.text(x, y, val).attr(styles.labels).attr({ 'text-anchor': 'end' });
                if (me.theme().columnChart.cutGridLines) ly += 10;

                if (val !== 0) {
                    lbl = me.__gridlabels[val] = me.__gridlabels[val] || me.label(x+2, ly, txt, { align: 'left', cl: 'axis', css: { opacity: 0 } });
                    lbl.animate({ x: x+2, y: ly, css: { opacity: 1 } }, me.theme().duration, me.theme().easing);
                }

                if (me.theme().yTicks) {
                    me.path([['M', c.lpad-25, y], ['L', c.lpad-20,y]], 'tick');
                }
                if (me.theme().horizontalGrid) {
                    var p = 'M' + [c.lpad, y] + 'H' + c.w,
                        l = me.__gridlines[val] = me.__gridlines[val] || me.path(p, 'grid').attr(me.theme().horizontalGrid).attr('opacity', 0);

                    if (val === 0) l.attr(me.theme().xAxis);
                    else if (me.theme().columnChart.cutGridLines) l.attr('stroke', me.theme().colors.background);

                    l.animate({ path: p, opacity: 1 }, me.theme().duration, me.theme().easing);
                    l.toBack();
                }
            });

            _.each(me.__gridlabels, function(lbl, val) {
                if (_.indexOf(ticks, +val) < 0) {
                    lbl.animate({ css: { opacity: 0 } }, me.theme().duration, me.theme().easing);
                }
            });
            _.each(me.__gridlines, function(line, val) {
                if (_.indexOf(ticks, +val) < 0) {
                    line.animate({ opacity: 0 }, me.theme().duration, me.theme().easing);
                }
            });
        },

        /*
         * highlights hovered bars and displays value labels
         */
        hover: function(hoveredSeries) {
            var me = this,
                whitishBg = chroma.color(me.theme().colors.background).lch()[0] > 60;

            // compute fill color, depending on hoveredSeries
            function getFill(col, el) {
                var fill = me.getColor(null, el.data('row'), { varyLightness: true, key: me.axes(true).labels.val(el.data('row')) });
                if (hoveredSeries !== undefined && col.name() == dw.utils.name(hoveredSeries)) {
                    fill = chroma.color(fill).darken(whitishBg ? 15 : -25).hex();
                }
                return fill;
            }

            _.each(me.getBarColumns(), function(column) {

                var fill, stroke;

                // highlight/invert the column title
                _.each(me.__labels[column.name()], function(lbl) {
                    if (hoveredSeries !== undefined && column.name() == dw.utils.name(hoveredSeries)) {
                        lbl.addClass('hover');
                        if (lbl.hasClass('showOnHover')) lbl.show(0.5);
                    } else {
                        lbl.removeClass('hover');
                        if (lbl.hasClass('showOnHover')) lbl.hide(0.5);
                    }
                    if (lbl.hasClass('value')) {
                        lbl.removeClass('hover');
                        fill = getFill(column, lbl);
                            lbl.addClass('inverted');
                        //}
                    }
                });
                // animate the bar fill & stroke
                _.each(me.__elements[column.name()], function(el) {
                    fill = getFill(column, el);
                    stroke = chroma.color(fill).darken(10).hex();
                    if (el.attrs.fill != fill || el.attrs.stroke != stroke)
                        el.animate({ fill: fill, stroke: stroke }, 50);
                });
            });

            // show/hide the labels that show values on top of the bars
            _.each(me.__barLbls, function(lbl, key) {
                if (hoveredSeries && lbl.data('key') == dw.utils.name(hoveredSeries)) lbl.show();
                else lbl.hide();
            });
        },

        unhoverSeries: function() {
            this.hoverSeries();
        },

        formatValue: function() {
            var me = this;
            // we're overwriting this function with the actual column formatter
            // when it is first called (lazy evaluation)
            me.formatValue = me.chart().columnFormatter(me.axes(true).columns[0]);
            return me.formatValue.apply(me, arguments);
        },

        post_render: function() {

        },

        checkData: function() {
            return true;
        }
    });

}).call(this);<|endoftext|>


<commit_before>function ol3MapEngine(selector, animate) {

  var baseLayers = {
    "Open Street Map": new ol.layer.Tile({
      source: new ol.source.OSM(),
      visible: false,
    }),
    "ESRI Ocean": new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}'
      }),
      visible: false,
    }),
    // Google Streets
    // Google Physical
    // Google Satellite
    // Nautical Charts
  };

  var baseLayerGroup = new ol.layer.Group({
    layers: _.values(baseLayers),
  });
  var dataLayerGroup = new ol.layer.Group({
    layers: [],
  });

  var view = new ol.View();

  var map = new ol.Map({
    target: selector,
    layers: [
      baseLayerGroup,
      dataLayerGroup,
    ],
    view: view,
    interactions: [],
    controls: [],
  });
  map.on("render", function(){
    console.log(e);
  });

  var typeCreateHandlers = {
    'XYZ': function(l) {
      var fixedUrlTemplate = l.url.replace(/\$\{([xyz])\}/g, '\{$1\}')
      return new ol.layer.Tile({
        source: new ol.source.XYZ({
          url: fixedUrlTemplate,
        })
      });
    },
    'Vector': function(l) {
      return new ol.layer.Vector({
        source: new ol.source.GeoJSON({
          url: l.url,
        }),
        style: new ol.style.Style({
          stroke: new ol.style.Stroke({
            color: l.vector_outline_color,
            width: 1.5,
          }),
          fill: new ol.style.Fill({
            color: l.vector_color,
          }),
        }),
        opacity: l.opacity,
      });
    },
    'WMS': function(l) {
      return new ol.layer.Tile({
        // extent: [-13884991, 2870341, -7455066, 6338219],
        source: new ol.source.TileWMS( ({
          url: l.url,
          params: {'LAYERS': l.arcgis_layers, 'TILED': true}
        }))
      })
    },
  }

  function wrapAnimations(animations, after) {
    return function(map, state) {
      for (i = 0; i < animations.length; ++i) {
        if (!animations[i](map, state)) {
          animations.splice(i--, 1);
        }
      }
      if (animations.length == 0) {
        after(map, state);
        return false;
      }
      return true;
    }
  }

  return {
    setView: function(center, zoom, afterFunc){
      console.info("set view center: " + center + ", zoom: " + zoom);
      // only animate if enabled and there is a previous view state
      if (animate && view.getCenter() && view.getZoom()) {
        // dataLayerGroup.setVisible(false);
        map.beforeRender(wrapAnimations([
          ol.animation.pan({
            duration: 2000,
            source: /** <at> type {ol.Coordinate} */ (view.getCenter())
          }),
          ol.animation.zoom({
            duration: 2000,
            resolution: view.getResolution(),
            source: /** <at> type {ol.Coordinate} */ (view.getZoom())
          })
          ], function() {
            afterFunc();
            dataLayerGroup.setVisible(true);
          })
        );
      } else {
        afterFunc();
      };

      view.setCenter(ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'));
      view.setZoom(zoom);
    },
    newDataLayer: function(l) {
      if (!typeCreateHandlers.hasOwnProperty(l.layer_type)) {
        console.warn("Unknown layer_type: " + l.layer_type);
        return null;
      }

      var layerObj = typeCreateHandlers[l.layer_type](l);
      layerObj.setVisible(false);
      dataLayerGroup.getLayers().push(layerObj);

      return layerObj;
    },
    showLayer: function(layer){ return layer.setVisible(true) },
    hideLayer: function(layer){ return layer.setVisible(false) },
    baseLayers: baseLayers,
    updateSize: function(){
      map.updateSize();
    }
  };
}
<commit_msg>add all the base layers<commit_after>function ol3MapEngine(selector, animate) {

  var baseLayers = {
    "Ocean": new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 17,
      }),
      visible: false,
    }),
    "Open Street Map": new ol.layer.Tile({
      source: new ol.source.OSM(),
      visible: false,
    }),
    "Streets": new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 17,
      }),
      visible: false,
    }),
    "Physical": new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 20,
      }),
      visible: false,
    }),
    "Satellite": new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 20,
      }),
      visible: false,
    }),
    "Nautical Charts": new ol.layer.Tile({
      source: new ol.source.TileWMS({
        url: "http://egisws02.nos.noaa.gov/ArcGIS/services/RNC/NOAA_RNC/ImageServer/WMSServer",
        maxZoom: 13,
        projection: "EPSG:3857",
      }),
      visible: false,
    }),
  };

  var baseLayerGroup = new ol.layer.Group({
    layers: _.values(baseLayers),
  });
  var dataLayerGroup = new ol.layer.Group({
    layers: [],
  });

  var view = new ol.View();

  var map = new ol.Map({
    target: selector,
    layers: [
      baseLayerGroup,
      dataLayerGroup,
    ],
    view: view,
    interactions: [],
    controls: [],
  });
  map.on("render", function(){
    console.log(e);
  });

  var typeCreateHandlers = {
    'XYZ': function(l) {
      var fixedUrlTemplate = l.url.replace(/\$\{([xyz])\}/g, '\{$1\}')
      return new ol.layer.Tile({
        source: new ol.source.XYZ({
          url: fixedUrlTemplate,
        })
      });
    },
    'Vector': function(l) {
      return new ol.layer.Vector({
        source: new ol.source.GeoJSON({
          url: l.url,
        }),
        style: new ol.style.Style({
          stroke: new ol.style.Stroke({
            color: l.vector_outline_color,
            width: 1.5,
          }),
          fill: new ol.style.Fill({
            color: l.vector_color,
          }),
        }),
        opacity: l.opacity,
      });
    },
    'WMS': function(l) {
      return new ol.layer.Tile({
        // extent: [-13884991, 2870341, -7455066, 6338219],
        source: new ol.source.TileWMS( ({
          url: l.url,
          params: {'LAYERS': l.arcgis_layers, 'TILED': true}
        }))
      })
    },
  }

  function wrapAnimations(animations, after) {
    return function(map, state) {
      for (i = 0; i < animations.length; ++i) {
        if (!animations[i](map, state)) {
          animations.splice(i--, 1);
        }
      }
      if (animations.length == 0) {
        after(map, state);
        return false;
      }
      return true;
    }
  }

  return {
    setView: function(center, zoom, afterFunc){
      console.info("set view center: " + center + ", zoom: " + zoom);
      // only animate if enabled and there is a previous view state
      if (animate && view.getCenter() && view.getZoom()) {
        // dataLayerGroup.setVisible(false);
        map.beforeRender(wrapAnimations([
          ol.animation.pan({
            duration: 2000,
            source: /** <at> type {ol.Coordinate} */ (view.getCenter())
          }),
          ol.animation.zoom({
            duration: 2000,
            resolution: view.getResolution(),
            source: /** <at> type {ol.Coordinate} */ (view.getZoom())
          })
          ], function() {
            afterFunc();
            dataLayerGroup.setVisible(true);
          })
        );
      } else {
        afterFunc();
      };

      view.setCenter(ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'));
      view.setZoom(zoom);
    },
    newDataLayer: function(l) {
      if (!typeCreateHandlers.hasOwnProperty(l.layer_type)) {
        console.warn("Unknown layer_type: " + l.layer_type);
        return null;
      }

      var layerObj = typeCreateHandlers[l.layer_type](l);
      layerObj.setVisible(false);
      dataLayerGroup.getLayers().push(layerObj);

      return layerObj;
    },
    showLayer: function(layer){ return layer.setVisible(true) },
    hideLayer: function(layer){ return layer.setVisible(false) },
    baseLayers: baseLayers,
    updateSize: function(){
      map.updateSize();
    }
  };
}
<|endoftext|>


<commit_before>
$(document).ready(function(){

	module("About Truthyness (topics/about_truthyness.js)");

	test("truthyness of positive numbers", function() {
		var oneIsTrue = 1 ? true : false;
		equals(oneIsTrue, __, 'is one true?');
	});

	test("truthyness of negative numbers", function() {
		var negativeOneIsTrue = -1 ? true : false;
		equals(negativeOneIsTrue, __, 'is -1 true?');
	});

	test("truthyness of zero", function() {
		var zeroIsTrue = 0 ? true : false;
		equals(zeroIsTrue, __, 'is 0 true?');
	});

	test("truthyness of null", function() {
		var nullIsTrue = null ? true : false;
		equals(nullIsTrue, __);
	});

});
<commit_msg>updated variable names and messages for about__truthyness<commit_after>
$(document).ready(function(){

	module("About Truthyness (topics/about_truthyness.js)");

	test("truthyness of positive numbers", function() {
		var oneIsTruthy = 1 ? true : false;
		equals(oneIsTruthy, __, 'is one truthy?');
	});

	test("truthyness of negative numbers", function() {
		var negativeOneIsTruthy = -1 ? true : false;
		equals(negativeOneIsTruthy, __, 'is -1 truthy?');
	});

	test("truthyness of zero", function() {
		var zeroIsTruthy = 0 ? true : false;
		equals(zeroIsTruthy, __, 'is 0 truthy?');
	});

	test("truthyness of null", function() {
		var nullIsTruthy = null ? true : false;
		equals(nullIsTruthy, __, 'is null truthy?');
	});

});
<|endoftext|>


<commit_before>/*
* @Author: justinwebb
* @Date:   2015-06-03 15:30:09
* @Last Modified by:   ChalrieHwang
* @Last Modified time: 2015-06-04 01:52:29
*/

'use strict';
(function (angular) {

  var GraphPanelCtrl = function ($scope) {
    var graphScope = $scope.$parent;
    $scope.onGraphClick = function($event){
      var clickObj = $event.target.__data__;
      if(graphScope.g.node(clickObj).class === 'cluster'){
        graphScope.buildGraph(graphScope.data);
      } else if (true) {

      }
    };

    $scope.mouseOverGraph = function($event){
      var mouseOverObj = $event.target.__data__;
      if(true){
      } ;
    };
  };

  var link = function ($scope, elem, attr) {
    console.log('GraphPanelDirective: ', elem);
  };

  var GraphPanelDirective = function () {

    return {
      restrict: 'E',
      scope: {
      },
      link: link,
      controller: GraphPanelCtrl,
      template:  [
        '
',
        '<svg id="canvas" ng-mouseover="mouseOver($event)" ng-click="onGraphClick($event)"><g/></svg>',
        '
'
      ].join('')
    };
  };

  angular
    .module('cd-app.common')
    .directive('dagreGraphPanel', GraphPanelDirective);
})(angular);
<commit_msg>(feat) Change the click event from one click to double click<commit_after>/*
* @Author: justinwebb
* @Date:   2015-06-03 15:30:09
* @Last Modified by:   cwhwang1986
* @Last Modified time: 2015-06-04 09:05:27
*/

'use strict';
(function (angular) {

  var GraphPanelCtrl = function ($scope) {
    var graphScope = $scope.$parent;
    $scope.onGraphClick = function($event){
      var clickObj = $event.target.__data__;
      if(graphScope.g.node(clickObj).class === 'cluster'){
        graphScope.buildGraph(graphScope.data);
      } else if (true) {

      }
    };

    $scope.mouseOverGraph = function($event){
      var mouseOverObj = $event.target.__data__;
      if(true){
      } ;
    };
  };

  var link = function ($scope, elem, attr) {
    console.log('GraphPanelDirective: ', elem);
  };

  var GraphPanelDirective = function () {

    return {
      restrict: 'E',
      scope: {
      },
      link: link,
      controller: GraphPanelCtrl,
      template:  [
        '
',
        '<svg id="canvas" ng-mouseover="mouseOver($event)" ng-dblclick="onGraphClick($event)"><g/></svg>',
        '
'
      ].join('')
    };
  };

  angular
    .module('cd-app.common')
    .directive('dagreGraphPanel', GraphPanelDirective);
})(angular);
<|endoftext|>


<commit_before>/*global cordova: true */
define(
  ['uuid'],
  function (uuid) {
    "use strict";
    var API = {
      getAnswerSpaceMap: function (user) {
        return new Promise(function (resolve, reject) {
          var userString = '';
          if (user) {
            userString = '&_username=' + user;
          }
          cordova.offline.retrieveContent(
            function (data) {
              resolve(JSON.parse(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetConfig.php?_asn=' + window.BMP.BIC.siteVars.answerSpace + userString
            }
          );
        });
      },

      getInteractionResult: function (iact, args) {
        var getargs = '';
        if (args && typeof args === "object") {
          _.each(args, function (value, key) {
            if (value) {
              getargs += '&' + key + '=' + value;
            }
          });
        }
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            resolve,
            reject,
            {
              url: '/_R_/common/3/xhr/GetAnswer.php?asn=' + window.BMP.BIC.siteVars.answerSpace + '&iact=' + iact + '&ajax=false' + getargs
            }
          );
        });
      },

      getForm: function () {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve(JSON.parse(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetForm.php?_v=3&_aid=' + window.BMP.BIC.siteVars.answerSpaceId
            }
          );
        });
      },

      getDataSuitcase: function (suitcase, time) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            resolve,
            reject,
            {
              url: '/_R_/common/3/xhr/GetMoJO.php?_id=' + window.BMP.BIC.siteVars.answerSpaceId + '&_m=' + suitcase + '&_lc=' + time
            }
          );
        });
      },

      setPendingItem: function (formname, formaction, formdata) {
        formdata._uuid = uuid.v4();
        return $.post('/_R_/common/3/xhr/SaveFormRecord.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formname + '&_action=' + formaction, formdata);
      },

      getLoginStatus: function () {
        return $.ajax('/_R_/common/3/xhr/GetLogin.php');
      },

      getFormList: function (formName) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve($.parseXML(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetFormList.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formName
            }
          );
        });
      },

      getFormRecord: function (formName, formAction, recordID) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve($.parseXML(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetFormRecord.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formName + '&_tid=' + recordID + '&action=' + formAction
            }
          );
        });
      }
    };

    return API;
  }
);
<commit_msg>Run MADL through the network instead of the offline plugin<commit_after>/*global cordova: true */
define(
  ['uuid'],
  function (uuid) {
    "use strict";
    var API = {
      getAnswerSpaceMap: function (user) {
        return new Promise(function (resolve, reject) {
          var userString = '';
          if (user) {
            userString = '&_username=' + user;
          }
          cordova.offline.retrieveContent(
            function (data) {
              resolve(JSON.parse(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetConfig.php?_asn=' + window.BMP.BIC.siteVars.answerSpace + userString
            }
          );
        });
      },

      getInteractionResult: function (iact, args, options) {
        var getargs = '';
        if (args && typeof args === "object") {
          _.each(args, function (value, key) {
            if (value) {
              getargs += '&' + key + '=' + value;
            }
          });
        }
        return $.ajax('/_R_/common/3/xhr/GetAnswer.php?asn=' + window.BMP.BIC.siteVars.answerSpace + '&iact=' + iact + '&ajax=false' + getargs, options);
      },

      getForm: function () {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve(JSON.parse(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetForm.php?_v=3&_aid=' + window.BMP.BIC.siteVars.answerSpaceId
            }
          );
        });
      },

      getDataSuitcase: function (suitcase, time) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            resolve,
            reject,
            {
              url: '/_R_/common/3/xhr/GetMoJO.php?_id=' + window.BMP.BIC.siteVars.answerSpaceId + '&_m=' + suitcase + '&_lc=' + time
            }
          );
        });
      },

      setPendingItem: function (formname, formaction, formdata) {
        formdata._uuid = uuid.v4();
        return $.post('/_R_/common/3/xhr/SaveFormRecord.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formname + '&_action=' + formaction, formdata);
      },

      getLoginStatus: function () {
        return $.ajax('/_R_/common/3/xhr/GetLogin.php');
      },

      getFormList: function (formName) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve($.parseXML(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetFormList.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formName
            }
          );
        });
      },

      getFormRecord: function (formName, formAction, recordID) {
        return new Promise(function (resolve, reject) {
          cordova.offline.retrieveContent(
            function (data) {
              resolve($.parseXML(data));
            },
            reject,
            {
              url: '/_R_/common/3/xhr/GetFormRecord.php?_asid=' + window.BMP.BIC.siteVars.answerSpaceId + '&_fn=' + formName + '&_tid=' + recordID + '&action=' + formAction
            }
          );
        });
      }
    };

    return API;
  }
);
<|endoftext|>


<commit_before>goog.provide('gmf.MobileNavController');
goog.provide('gmf.mobileNavDirective');

goog.require('gmf');

/**
 * An "gmf-nav" directive defining the behavior of a tree-structured menu.
 *
 * The directive is to be placed on a `nav` element, with the following
 * structure:
 *
 *
 *
 *     Categories
 *
 *

 *

 *       Devices
 *

 *

 *           Mobile Phones
 *

 *

 *           Televisions
 *

 *

 *

 *

 *       Cars
 *

 *

 *           Camping Cars
 *

 *

 *

 *

 *
 *
 * When an element slides in the directive changes the text in the header.
 *
 * @return {angular.Directive} The Directive Definition Object.
 * @ngInject
 */
gmf.mobileNavDirective = function() {
  return {
    restrict: 'A',
    controller: 'gmfMobileNavController',
    bindToController: true,
    controllerAs: 'navCtrl',
    scope: true,
    link:
        /**
         * @param {angular.Scope} scope Scope.
         * @param {angular.JQLite} element Element.
         * @param {angular.Attributes} attrs Atttributes.
         * @param {gmf.MobileNavController} navCtrl Controller.
         */
        function(scope, element, attrs, navCtrl) {
          navCtrl.init(element);
        }
  };
};

gmf.module.directive('gmfMobileNav', gmf.mobileNavDirective);

/**
* @constructor
* @export
* @ngInject
* @ngdoc controller
* @ngname gmfMobileNavController
*/
gmf.MobileNavController = function() {
  /**
   * Stack of slid-in items.
   * @private
   * @type {Array.<!jQuery>}
   */
  this.slid_ = [];

  /**
   * Currently active sliding box.
   * @private
   * @type {jQuery}
   */
  this.active_ = null;

  /**
   * The navigation header.
   * @private
   * @type {jQuery}
   */
  this.header_ = null;

  /**
   * The back button in the navigation header.
   * @private
   * @type {jQuery}
   */
  this.backButton_ = null;

  /**
   * Export the back function already bound to `this`. This makes sure that
   * the function is called on the right context, when it is passed to an
   * attribute in a template
   * @export
   */
  this.back = this.back_.bind(this);
};

gmf.module.controller('gmfMobileNavController', gmf.MobileNavController);

/**
 * Initialize the directive with the linked element.
 * @param {angular.JQLite} element Element.
 */
gmf.MobileNavController.prototype.init = function(element) {
  this.active_ = $(element.find('.active.slide'));
  this.header_ = $(element.find('> header'));
  this.backButton_ = $(element.find('header > .go-back'));

  // watch for clicks on "slide-in" elements
  element.find('[data-toggle=slide-in]').on('click', function(evt) {

    // the element to slide out is the div.slide parent
    var slideOut = $(evt.target).parents('.slide');

    // push the item to the selected stack
    this.slid_.push(slideOut);

    // slide the "old" element out
    slideOut.addClass('slide-out').removeClass('active');

    // element to slide in
    var slideIn = $($(evt.target).attr('data-target'));

    // slide the "new" element in
    slideIn.addClass('active');

    // update the navigation header
    this.updateNavigationHeader_(slideIn, false);

    this.active_ = slideIn;
  }.bind(this));

  // watch for clicks on the header "go-back" link
  this.backButton_.click(this.back.bind(this));
};

/**
 * @param {!jQuery} active The currently active sliding box.
 * @param {boolean} back Whether to move back.
 * @private
 */
gmf.MobileNavController.prototype.updateNavigationHeader_ = function(
    active, back) {
  this.header_.toggleClass('back', back);

  // remove any inactive nav
  this.header_.find('nav:not(.active)').remove();

  // deactivate the currently active nav
  this.header_.find('nav.active').removeClass('active')
      .addClass('slide-out');

  // show the back button when relevant
  this.backButton_.toggleClass('active', this.slid_.length > 0);

  // create a new nav
  var nav = $('');
  nav.append($('', {
    text: active.attr('data-header-title')
  }));
  this.header_.append(nav);

  // Delay the activation of the new navigation so that the previous
  // one is properly deactivated. This prevents weird animation
  // effects.
  window.setTimeout(function() {
    // fix for safari: the following 3 lines force that the position
    // of the newly inserted element is calculated.
    // see http://stackoverflow.com/a/3485654/119937
    nav.css('display', 'none');
    nav.offset();
    nav.css('display', '');

    window.setTimeout(function() {
      // fix: calling `position()` makes sure that the animation
      // is always run
      nav.position();
      nav.addClass('active');
    }, 0);
  }, 0);
};

gmf.module.controller('gmfMobileNavController', gmf.MobileNavController);

/**
 * Return to the previous slide.
 * @private
 */
gmf.MobileNavController.prototype.back_ = function() {
  if (this.slid_.length <= 0) {
    return;
  }

  // slide active item to the right
  this.active_.removeClass('active');

  // get the previously active item
  var slideBack = this.slid_.pop();

  // slide previous item to the right
  slideBack.addClass('active').removeClass('slide-out');

  // update the navigation header
  this.updateNavigationHeader_(slideBack, true);

  this.active_ = slideBack;
};

/**
 * Return to the previous slide if the given element is active.
 *
 * @param {Element} element The element to check.
 */
gmf.MobileNavController.prototype.backIfActive = function(element) {
  if (this.active_ !== null && this.active_.is(element)) {
    this.back_();
  }
};

/**
 * A directive to be used in conjunction with {@link gmf.mobileNavDirective}.
 * The directive can be set on a slide element of {@link gmf.mobileNavDirective}
 * with an expression. When the value of the expression changes, the navigation
 * returns to the previous slide, if the slide is currently active.
 *
 * Example:
 *
 *
 *      ...
 *      <gmf-themeselector
 *         id="themes"
 *         class="slide"
 *         data-header-title="Themes"
 *         gmf-themeselector-currenttheme="mainCtrl.theme"
 *         gmf-mobile-nav-back="mainCtrl.theme">
 *      </gmf-themeselector>
 *
 * If `mainCtrl.theme` changes and the theme-selector slide is currently active,
 * the navigation will go back to the last slide.
 *
 * @return {angular.Directive} The Directive Definition Object.
 * @ngInject
 */
gmf.mobileNavBackDirective = function() {
  return {
    require: '^^gmfMobileNav',
    restrict: 'A',
    scope: false,
    link:
        /**
         * @param {angular.Scope} scope Scope.
         * @param {angular.JQLite} element Element.
         * @param {angular.Attributes} attrs Atttributes.
         * @param {gmf.MobileNavController} navCtrl Controller.
         */
        function(scope, element, attrs, navCtrl) {
          scope.$watch(attrs['gmfMobileNavBack'], function(newVal, oldVal) {
            navCtrl.backIfActive(element[0]);
          });
        }
  };
};

gmf.module.directive('gmfMobileNavBack', gmf.mobileNavBackDirective);
<commit_msg>update gmf-mobile-nav example in doc comments<commit_after>goog.provide('gmf.MobileNavController');
goog.provide('gmf.mobileNavDirective');

goog.require('gmf');

/**
 * An "gmf-mobile-nav" directive defining the behavior of a tree-structured menu.
 *
 * The directive is to be placed on a `nav` element, with the following
 * structure:
 *
 *
 *
 *
 *

 *

 *

 *         Devices
 *

 *

 *         Vehicles
 *

 *

 *

 *

 *

 *
Mobile Phones

 *
Televisions

 *

 *

 *

 *

 *
Cars

 *
Planes

 *
Bicycles

 *

 *

 *
 *
 * When an element slides in the directive changes the text in the header.
 *
 * @return {angular.Directive} The Directive Definition Object.
 * @ngInject
 */
gmf.mobileNavDirective = function() {
  return {
    restrict: 'A',
    controller: 'gmfMobileNavController',
    bindToController: true,
    controllerAs: 'navCtrl',
    scope: true,
    link:
        /**
         * @param {angular.Scope} scope Scope.
         * @param {angular.JQLite} element Element.
         * @param {angular.Attributes} attrs Atttributes.
         * @param {gmf.MobileNavController} navCtrl Controller.
         */
        function(scope, element, attrs, navCtrl) {
          navCtrl.init(element);
        }
  };
};

gmf.module.directive('gmfMobileNav', gmf.mobileNavDirective);

/**
* @constructor
* @export
* @ngInject
* @ngdoc controller
* @ngname gmfMobileNavController
*/
gmf.MobileNavController = function() {
  /**
   * Stack of slid-in items.
   * @private
   * @type {Array.<!jQuery>}
   */
  this.slid_ = [];

  /**
   * Currently active sliding box.
   * @private
   * @type {jQuery}
   */
  this.active_ = null;

  /**
   * The navigation header.
   * @private
   * @type {jQuery}
   */
  this.header_ = null;

  /**
   * The back button in the navigation header.
   * @private
   * @type {jQuery}
   */
  this.backButton_ = null;

  /**
   * Export the back function already bound to `this`. This makes sure that
   * the function is called on the right context, when it is passed to an
   * attribute in a template
   * @export
   */
  this.back = this.back_.bind(this);
};

gmf.module.controller('gmfMobileNavController', gmf.MobileNavController);

/**
 * Initialize the directive with the linked element.
 * @param {angular.JQLite} element Element.
 */
gmf.MobileNavController.prototype.init = function(element) {
  this.active_ = $(element.find('.active.slide'));
  this.header_ = $(element.find('> header'));
  this.backButton_ = $(element.find('header > .go-back'));

  // watch for clicks on "slide-in" elements
  element.find('[data-toggle=slide-in]').on('click', function(evt) {

    // the element to slide out is the div.slide parent
    var slideOut = $(evt.target).parents('.slide');

    // push the item to the selected stack
    this.slid_.push(slideOut);

    // slide the "old" element out
    slideOut.addClass('slide-out').removeClass('active');

    // element to slide in
    var slideIn = $($(evt.target).attr('data-target'));

    // slide the "new" element in
    slideIn.addClass('active');

    // update the navigation header
    this.updateNavigationHeader_(slideIn, false);

    this.active_ = slideIn;
  }.bind(this));

  // watch for clicks on the header "go-back" link
  this.backButton_.click(this.back.bind(this));
};

/**
 * @param {!jQuery} active The currently active sliding box.
 * @param {boolean} back Whether to move back.
 * @private
 */
gmf.MobileNavController.prototype.updateNavigationHeader_ = function(
    active, back) {
  this.header_.toggleClass('back', back);

  // remove any inactive nav
  this.header_.find('nav:not(.active)').remove();

  // deactivate the currently active nav
  this.header_.find('nav.active').removeClass('active')
      .addClass('slide-out');

  // show the back button when relevant
  this.backButton_.toggleClass('active', this.slid_.length > 0);

  // create a new nav
  var nav = $('');
  nav.append($('', {
    text: active.attr('data-header-title')
  }));
  this.header_.append(nav);

  // Delay the activation of the new navigation so that the previous
  // one is properly deactivated. This prevents weird animation
  // effects.
  window.setTimeout(function() {
    // fix for safari: the following 3 lines force that the position
    // of the newly inserted element is calculated.
    // see http://stackoverflow.com/a/3485654/119937
    nav.css('display', 'none');
    nav.offset();
    nav.css('display', '');

    window.setTimeout(function() {
      // fix: calling `position()` makes sure that the animation
      // is always run
      nav.position();
      nav.addClass('active');
    }, 0);
  }, 0);
};

gmf.module.controller('gmfMobileNavController', gmf.MobileNavController);

/**
 * Return to the previous slide.
 * @private
 */
gmf.MobileNavController.prototype.back_ = function() {
  if (this.slid_.length <= 0) {
    return;
  }

  // slide active item to the right
  this.active_.removeClass('active');

  // get the previously active item
  var slideBack = this.slid_.pop();

  // slide previous item to the right
  slideBack.addClass('active').removeClass('slide-out');

  // update the navigation header
  this.updateNavigationHeader_(slideBack, true);

  this.active_ = slideBack;
};

/**
 * Return to the previous slide if the given element is active.
 *
 * @param {Element} element The element to check.
 */
gmf.MobileNavController.prototype.backIfActive = function(element) {
  if (this.active_ !== null && this.active_.is(element)) {
    this.back_();
  }
};

/**
 * A directive to be used in conjunction with {@link gmf.mobileNavDirective}.
 * The directive can be set on a slide element of {@link gmf.mobileNavDirective}
 * with an expression. When the value of the expression changes, the navigation
 * returns to the previous slide, if the slide is currently active.
 *
 * Example:
 *
 *
 *      ...
 *      <gmf-themeselector
 *         id="themes"
 *         class="slide"
 *         data-header-title="Themes"
 *         gmf-themeselector-currenttheme="mainCtrl.theme"
 *         gmf-mobile-nav-back="mainCtrl.theme">
 *      </gmf-themeselector>
 *
 * If `mainCtrl.theme` changes and the theme-selector slide is currently active,
 * the navigation will go back to the last slide.
 *
 * @return {angular.Directive} The Directive Definition Object.
 * @ngInject
 */
gmf.mobileNavBackDirective = function() {
  return {
    require: '^^gmfMobileNav',
    restrict: 'A',
    scope: false,
    link:
        /**
         * @param {angular.Scope} scope Scope.
         * @param {angular.JQLite} element Element.
         * @param {angular.Attributes} attrs Atttributes.
         * @param {gmf.MobileNavController} navCtrl Controller.
         */
        function(scope, element, attrs, navCtrl) {
          scope.$watch(attrs['gmfMobileNavBack'], function(newVal, oldVal) {
            navCtrl.backIfActive(element[0]);
          });
        }
  };
};

gmf.module.directive('gmfMobileNavBack', gmf.mobileNavBackDirective);
<|endoftext|>


<commit_before>
angular.module('os.biospecimen.visit.addedit', [])
  .controller('AddEditVisitCtrl', function(
    $scope, $state, $stateParams, cp, cpr, visit, latestVisit, extensionCtxt, hasDict, layout, mrnAccessRestriction,
    ParticipantSpecimensViewState, PvManager, ExtensionsUtil) {

    function loadPvs() {
      $scope.visitStatuses = PvManager.getPvs('visit-status');
      $scope.cohorts = PvManager.getPvs('cohort');
    };

    function init() {
      var currVisit = $scope.currVisit = angular.copy(visit);
      angular.extend(currVisit, {cprId: cpr.id, cpTitle: cpr.cpTitle});

      $scope.visitCtx = {
        obj: {visit: $scope.currVisit, cp: cp},
        opts: {layout: layout, mdInput: false},
        inObjs: ['visit'],
        mrnAccessRestriction: mrnAccessRestriction
      }

      if (!currVisit.id) {
        angular.extend(currVisit, {
          visitDate: currVisit.anticipatedVisitDate || new Date(),
          status: 'Complete',
          clinicalDiagnoses: latestVisit ? latestVisit.clinicalDiagnoses : currVisit.clinicalDiagnoses,
          site: getVisitSite(cpr, latestVisit, currVisit)
        });
        delete currVisit.anticipatedVisitDate;
      }

      if ($stateParams.missedVisit == 'true') {
        angular.extend(currVisit, {status: 'Missed Collection'});
      } else if ($stateParams.newVisit == 'true') {
        angular.extend(currVisit, {id: undefined, name: undefined, status: 'Complete', visitDate: new Date()});
      }

      $scope.deFormCtrl = {};
      $scope.extnOpts = ExtensionsUtil.getExtnOpts(currVisit, extensionCtxt);

      if (!hasDict) {
        loadPvs();
      }
    }

    function getVisitSite(cpr, latestVisit, currVisit) {
      var site = currVisit.site;
      if (!!site) {
        // site = site;
      } else if (latestVisit) {
        site = latestVisit.site;
      } else if (cpr.participant.pmis.length > 0) {
        site = cpr.participant.pmis[0].siteName;
      }

      return site;
    }

    $scope.saveVisit = function() {
      var formCtrl = $scope.deFormCtrl.ctrl;
      if (formCtrl && !formCtrl.validate()) {
        return;
      }

      if (formCtrl) {
        $scope.currVisit.extensionDetail = formCtrl.getFormData();
      }

      $scope.currVisit.$saveOrUpdate().then(
        function(result) {
          ParticipantSpecimensViewState.specimensUpdated($scope);

          angular.extend($scope.visit, result);
          $state.go('visit-detail.overview', {visitId: result.id, eventId: result.eventId});
        }
      );
    };

    init();
  });
<commit_msg>Remove the event ID from the create visit payload when the event label differs from that of the copied visit. This is an indication that the UI might have an event label dropdown and the user might have selected some other event for visit.<commit_after>
angular.module('os.biospecimen.visit.addedit', [])
  .controller('AddEditVisitCtrl', function(
    $scope, $state, $stateParams, cp, cpr, visit, latestVisit, extensionCtxt, hasDict, layout, mrnAccessRestriction,
    ParticipantSpecimensViewState, PvManager, ExtensionsUtil) {

    function loadPvs() {
      $scope.visitStatuses = PvManager.getPvs('visit-status');
      $scope.cohorts = PvManager.getPvs('cohort');
    };

    function init() {
      var currVisit = $scope.currVisit = angular.copy(visit);
      angular.extend(currVisit, {cprId: cpr.id, cpTitle: cpr.cpTitle});

      $scope.visitCtx = {
        obj: {visit: $scope.currVisit, cp: cp},
        opts: {layout: layout, mdInput: false},
        inObjs: ['visit'],
        mrnAccessRestriction: mrnAccessRestriction
      }

      if (!currVisit.id) {
        angular.extend(currVisit, {
          visitDate: currVisit.anticipatedVisitDate || new Date(),
          status: 'Complete',
          clinicalDiagnoses: latestVisit ? latestVisit.clinicalDiagnoses : currVisit.clinicalDiagnoses,
          site: getVisitSite(cpr, latestVisit, currVisit)
        });
        delete currVisit.anticipatedVisitDate;
      }

      if ($stateParams.missedVisit == 'true') {
        angular.extend(currVisit, {status: 'Missed Collection'});
      } else if ($stateParams.newVisit == 'true') {
        angular.extend(currVisit, {id: undefined, name: undefined, status: 'Complete', visitDate: new Date()});
      }

      $scope.deFormCtrl = {};
      $scope.extnOpts = ExtensionsUtil.getExtnOpts(currVisit, extensionCtxt);

      if (!hasDict) {
        loadPvs();
      }
    }

    function getVisitSite(cpr, latestVisit, currVisit) {
      var site = currVisit.site;
      if (!!site) {
        // site = site;
      } else if (latestVisit) {
        site = latestVisit.site;
      } else if (cpr.participant.pmis.length > 0) {
        site = cpr.participant.pmis[0].siteName;
      }

      return site;
    }

    $scope.saveVisit = function() {
      var formCtrl = $scope.deFormCtrl.ctrl;
      if (formCtrl && !formCtrl.validate()) {
        return;
      }

      if (formCtrl) {
        $scope.currVisit.extensionDetail = formCtrl.getFormData();
      }

      if ($scope.currVisit.eventLabel != visit.eventLabel) {
        $scope.currVisit.eventId = undefined;
      }

      $scope.currVisit.$saveOrUpdate().then(
        function(result) {
          ParticipantSpecimensViewState.specimensUpdated($scope);

          angular.extend($scope.visit, result);
          $state.go('visit-detail.overview', {visitId: result.id, eventId: result.eventId});
        }
      );
    };

    init();
  });
<|endoftext|>


<commit_before>import React from 'react';
import Select from 'react-select';
import Routes from '../../services/Routes';
import TopBar from '../TopBar/TopBar';
import { ApiRequest } from '../../services/ApiRequest';
import DateFormatter from '../../utils/DateFormatter';

export default class AddNewMeal extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            message: this.getRetrievingYourRecopesMessage(),
            isAddMealVisible: false,
            recipes: [],
            selectedRecipeId: null
        };

        this.saveMeal = this.saveMeal.bind(this);
    }

    getMealDate() {
        return DateFormatter.stringToDate(this.props.location.query.mealDate);
    }

    componentDidMount() {
        ApiRequest.retrieveRecipes()
            .then(rsp => {
                const recipes = rsp.body;
                const recipesOptions = recipes.map(recipe => ({ value: recipe.id, label: recipe.name }));
                this.setState({ isAddMealVisible: true, message: null, recipes: recipesOptions });
            }, err => {
                this.setState({ message: this.getErrorMessage() });
            });
    }

    onRecipeChanged(recipe) {
        this.setState({ selectedRecipeId: recipe.value })
    }

    getRetrievingYourRecopesMessage() {
        return (

Retrieving your recipes...

        );
    }

    getSavingYourMealMessage() {
        return (

Saving your meal...

        );
    }

    getErrorMessage() {
        return (

 There was an error with our server. Please try again!

        );
    }

    getErrorMessageForInvalidDate() {
        const mealDate = this.props.location.query.mealDate;

        const message = mealDate ? `This meal date is not a valid date: ${mealDate}` : 'You do not have a meal date. Please go back to meal planner.';
        return (

 {message}

        );
    }

    saveMeal() {
        const mealDate = this.getMealDate();
        if (!mealDate.isValid()) {
            this.setState({ message: this.getErrorMessageForInvalidDate() });
            return;
        }

        this.setState({ message: this.getSavingYourMealMessage(), isAddMealVisible: false });
        const { mealOrder } = this.props.location.query;
        ApiRequest.addMealFromExistingRecipe(this.state.selectedRecipeId, DateFormatter.dateToIsoString(mealDate), mealOrder || 0)
            .then(rsp => {
                this.props.router.push(Routes.mealPlannerWithDate(DateFormatter.dateToString(mealDate)));
            }, err => {
                this.setState({ message: this.getErrorMessage(), isAddMealVisible: true })
            });
    }

    renderBody() {
        if (!this.state.isAddMealVisible) {
            return null;
        }

        return (

                    Add meal from existing recipes

                    <Select
                        options={this.state.recipes}
                        value={this.state.selectedRecipeId}
                        onChange={option => this.onRecipeChanged(option)}
                        clearable={true}
                        searchable={true}
                        placeholder="Select recipe"
                    // noResultsText={<button> Create this recipe </button>}
                    />

        );
    }

    render() {
        return (

                <TopBar
                    hideLogo
                    backButton backButtonText="Add meal" backButtonOnClick={() => this.props.router.push(Routes.mealPlanner())}
                    saveButton saveButtonOnClick={this.saveMeal} />

                    {this.state.message}
                    {this.renderBody()}

        );
    }
}<commit_msg>Send date as utc in add new meal<commit_after>import React from 'react';
import Select from 'react-select';
import Routes from '../../services/Routes';
import TopBar from '../TopBar/TopBar';
import { ApiRequest } from '../../services/ApiRequest';
import DateFormatter from '../../utils/DateFormatter';

export default class AddNewMeal extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            message: this.getRetrievingYourRecopesMessage(),
            isAddMealVisible: false,
            recipes: [],
            selectedRecipeId: null
        };

        this.saveMeal = this.saveMeal.bind(this);
    }

    getMealDate() {
        return DateFormatter.markLocaleDateAsUtc(DateFormatter.stringToDate(this.props.location.query.mealDate));
    }

    componentDidMount() {
        ApiRequest.retrieveRecipes()
            .then(rsp => {
                const recipes = rsp.body;
                const recipesOptions = recipes.map(recipe => ({ value: recipe.id, label: recipe.name }));
                this.setState({ isAddMealVisible: true, message: null, recipes: recipesOptions });
            }, err => {
                this.setState({ message: this.getErrorMessage() });
            });
    }

    onRecipeChanged(recipe) {
        this.setState({ selectedRecipeId: recipe.value })
    }

    getRetrievingYourRecopesMessage() {
        return (

Retrieving your recipes...

        );
    }

    getSavingYourMealMessage() {
        return (

Saving your meal...

        );
    }

    getErrorMessage() {
        return (

 There was an error with our server. Please try again!

        );
    }

    getErrorMessageForInvalidDate() {
        const mealDate = this.props.location.query.mealDate;

        const message = mealDate ? `This meal date is not a valid date: ${mealDate}` : 'You do not have a meal date. Please go back to meal planner.';
        return (

 {message}

        );
    }

    saveMeal() {
        const mealDate = this.getMealDate();
        if (!mealDate.isValid()) {
            this.setState({ message: this.getErrorMessageForInvalidDate() });
            return;
        }

        this.setState({ message: this.getSavingYourMealMessage(), isAddMealVisible: false });
        const { mealOrder } = this.props.location.query;
        ApiRequest.addMealFromExistingRecipe(this.state.selectedRecipeId, DateFormatter.dateToIsoString(mealDate), mealOrder || 0)
            .then(rsp => {
                this.props.router.push(Routes.mealPlannerWithDate(DateFormatter.dateToString(mealDate)));
            }, err => {
                this.setState({ message: this.getErrorMessage(), isAddMealVisible: true })
            });
    }

    renderBody() {
        if (!this.state.isAddMealVisible) {
            return null;
        }

        return (

                    Add meal from existing recipes

                    <Select
                        options={this.state.recipes}
                        value={this.state.selectedRecipeId}
                        onChange={option => this.onRecipeChanged(option)}
                        clearable={true}
                        searchable={true}
                        placeholder="Select recipe"
                    // noResultsText={<button> Create this recipe </button>}
                    />

        );
    }

    render() {
        return (

                <TopBar
                    hideLogo
                    backButton backButtonText="Add meal" backButtonOnClick={() => this.props.router.push(Routes.mealPlanner())}
                    saveButton saveButtonOnClick={this.saveMeal} />

                    {this.state.message}
                    {this.renderBody()}

        );
    }
}<|endoftext|>