You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

route.js 2.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. const conversions = require('./conversions');
  2. /*
  3. This function routes a model to all other models.
  4. all functions that are routed have a property `.conversion` attached
  5. to the returned synthetic function. This property is an array
  6. of strings, each with the steps in between the 'from' and 'to'
  7. color models (inclusive).
  8. conversions that are not possible simply are not included.
  9. */
  10. function buildGraph() {
  11. const graph = {};
  12. // https://jsperf.com/object-keys-vs-for-in-with-closure/3
  13. const models = Object.keys(conversions);
  14. for (let len = models.length, i = 0; i < len; i++) {
  15. graph[models[i]] = {
  16. // http://jsperf.com/1-vs-infinity
  17. // micro-opt, but this is simple.
  18. distance: -1,
  19. parent: null
  20. };
  21. }
  22. return graph;
  23. }
  24. // https://en.wikipedia.org/wiki/Breadth-first_search
  25. function deriveBFS(fromModel) {
  26. const graph = buildGraph();
  27. const queue = [fromModel]; // Unshift -> queue -> pop
  28. graph[fromModel].distance = 0;
  29. while (queue.length) {
  30. const current = queue.pop();
  31. const adjacents = Object.keys(conversions[current]);
  32. for (let len = adjacents.length, i = 0; i < len; i++) {
  33. const adjacent = adjacents[i];
  34. const node = graph[adjacent];
  35. if (node.distance === -1) {
  36. node.distance = graph[current].distance + 1;
  37. node.parent = current;
  38. queue.unshift(adjacent);
  39. }
  40. }
  41. }
  42. return graph;
  43. }
  44. function link(from, to) {
  45. return function (args) {
  46. return to(from(args));
  47. };
  48. }
  49. function wrapConversion(toModel, graph) {
  50. const path = [graph[toModel].parent, toModel];
  51. let fn = conversions[graph[toModel].parent][toModel];
  52. let cur = graph[toModel].parent;
  53. while (graph[cur].parent) {
  54. path.unshift(graph[cur].parent);
  55. fn = link(conversions[graph[cur].parent][cur], fn);
  56. cur = graph[cur].parent;
  57. }
  58. fn.conversion = path;
  59. return fn;
  60. }
  61. module.exports = function (fromModel) {
  62. const graph = deriveBFS(fromModel);
  63. const conversion = {};
  64. const models = Object.keys(graph);
  65. for (let len = models.length, i = 0; i < len; i++) {
  66. const toModel = models[i];
  67. const node = graph[toModel];
  68. if (node.parent === null) {
  69. // No possible conversion, or this node is the source model.
  70. continue;
  71. }
  72. conversion[toModel] = wrapConversion(toModel, graph);
  73. }
  74. return conversion;
  75. };