+ bokeh plugin
This commit is contained in:
parent
b36c3999dd
commit
a0f286d516
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,13 @@
|
||||||
|
var _;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
LinAlg: require("./api/linalg"),
|
||||||
|
Charts: require("./api/charts"),
|
||||||
|
Plotting: require("./api/plotting"),
|
||||||
|
Document: require("./document").Document,
|
||||||
|
sprintf: require("sprintf")
|
||||||
|
};
|
||||||
|
|
||||||
|
_.extend(module.exports, require("./api/models"));
|
|
@ -0,0 +1,467 @@
|
||||||
|
var $, Document, _, bar, cumsum, embed, hexcolor2rgb, is_dark, models, num2hexcolor, palettes, pie, sprintf, sum;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
sprintf = require("sprintf");
|
||||||
|
|
||||||
|
Document = require("../document").Document;
|
||||||
|
|
||||||
|
embed = require("../embed");
|
||||||
|
|
||||||
|
models = require("./models");
|
||||||
|
|
||||||
|
palettes = require("../palettes/palettes");
|
||||||
|
|
||||||
|
sum = function(array) {
|
||||||
|
return array.reduce(((function(_this) {
|
||||||
|
return function(a, b) {
|
||||||
|
return a + b;
|
||||||
|
};
|
||||||
|
})(this)), 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
cumsum = function(array) {
|
||||||
|
var result;
|
||||||
|
result = [];
|
||||||
|
array.reduce((function(a, b, i) {
|
||||||
|
return result[i] = a + b;
|
||||||
|
}), 0);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
num2hexcolor = function(num) {
|
||||||
|
return sprintf("#%06x", num);
|
||||||
|
};
|
||||||
|
|
||||||
|
hexcolor2rgb = function(color) {
|
||||||
|
var b, g, r;
|
||||||
|
r = parseInt(color.substr(1, 2), 16);
|
||||||
|
g = parseInt(color.substr(3, 2), 16);
|
||||||
|
b = parseInt(color.substr(5, 2), 16);
|
||||||
|
return [r, g, b];
|
||||||
|
};
|
||||||
|
|
||||||
|
is_dark = function(arg) {
|
||||||
|
var b, g, l, r;
|
||||||
|
r = arg[0], g = arg[1], b = arg[2];
|
||||||
|
l = 1 - (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||||
|
return l >= 0.6;
|
||||||
|
};
|
||||||
|
|
||||||
|
pie = function(data, opts) {
|
||||||
|
var angle_span, colors, cumulative_values, cx, cy, end_angle, end_angles, g1, g2, h1, half_angles, half_radius, hover, i, inner_radius, k, labels, normalized_values, outer_radius, palette, plot, r1, r2, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, source, start_angle, start_angles, text_angles, text_colors, text_cx, text_cy, to_cartesian, to_radians, tooltip, total_value, values, xdr, ydr;
|
||||||
|
if (opts == null) {
|
||||||
|
opts = {};
|
||||||
|
}
|
||||||
|
labels = [];
|
||||||
|
values = [];
|
||||||
|
for (i = k = 0, ref = Math.min(data.labels.length, data.values.length); 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
|
||||||
|
if (data.values[i] > 0) {
|
||||||
|
labels.push(data.labels[i]);
|
||||||
|
values.push(data.values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start_angle = (ref1 = opts.start_angle) != null ? ref1 : 0;
|
||||||
|
end_angle = (ref2 = opts.end_angle) != null ? ref2 : start_angle + 2 * Math.PI;
|
||||||
|
angle_span = Math.abs(end_angle - start_angle);
|
||||||
|
to_radians = function(x) {
|
||||||
|
return angle_span * x;
|
||||||
|
};
|
||||||
|
total_value = sum(values);
|
||||||
|
normalized_values = values.map(function(v) {
|
||||||
|
return v / total_value;
|
||||||
|
});
|
||||||
|
cumulative_values = cumsum(normalized_values);
|
||||||
|
end_angles = cumulative_values.map(function(v) {
|
||||||
|
return start_angle + to_radians(v);
|
||||||
|
});
|
||||||
|
start_angles = [start_angle].concat(end_angles.slice(0, -1));
|
||||||
|
half_angles = _.zip(start_angles, end_angles).map((function(_this) {
|
||||||
|
return function(arg) {
|
||||||
|
var end, start;
|
||||||
|
start = arg[0], end = arg[1];
|
||||||
|
return (start + end) / 2;
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
if (opts.center == null) {
|
||||||
|
cx = 0;
|
||||||
|
cy = 0;
|
||||||
|
} else if (_.isArray(opts.center)) {
|
||||||
|
cx = opts.center[0];
|
||||||
|
cy = opts.center[1];
|
||||||
|
} else {
|
||||||
|
cx = opts.center.x;
|
||||||
|
cy = opts.center.y;
|
||||||
|
}
|
||||||
|
inner_radius = (ref3 = opts.inner_radius) != null ? ref3 : 0;
|
||||||
|
outer_radius = (ref4 = opts.outer_radius) != null ? ref4 : 1;
|
||||||
|
if (_.isArray(opts.palette)) {
|
||||||
|
palette = opts.palette;
|
||||||
|
} else {
|
||||||
|
palette = palettes[(ref5 = opts.palette) != null ? ref5 : "Spectral11"].map(num2hexcolor);
|
||||||
|
}
|
||||||
|
colors = (function() {
|
||||||
|
var m, ref6, results;
|
||||||
|
results = [];
|
||||||
|
for (i = m = 0, ref6 = normalized_values.length; 0 <= ref6 ? m < ref6 : m > ref6; i = 0 <= ref6 ? ++m : --m) {
|
||||||
|
results.push(palette[i % palette.length]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
text_colors = colors.map(function(c) {
|
||||||
|
if (is_dark(hexcolor2rgb(c))) {
|
||||||
|
return "white";
|
||||||
|
} else {
|
||||||
|
return "black";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
to_cartesian = function(r, alpha) {
|
||||||
|
return [r * Math.cos(alpha), r * Math.sin(alpha)];
|
||||||
|
};
|
||||||
|
half_radius = (inner_radius + outer_radius) / 2;
|
||||||
|
ref6 = _.unzip(half_angles.map((function(_this) {
|
||||||
|
return function(half_angle) {
|
||||||
|
return to_cartesian(half_radius, half_angle);
|
||||||
|
};
|
||||||
|
})(this))), text_cx = ref6[0], text_cy = ref6[1];
|
||||||
|
text_cx = text_cx.map(function(x) {
|
||||||
|
return x + cx;
|
||||||
|
});
|
||||||
|
text_cy = text_cy.map(function(y) {
|
||||||
|
return y + cy;
|
||||||
|
});
|
||||||
|
text_angles = half_angles.map(function(a) {
|
||||||
|
if (a >= Math.PI / 2 && a <= 3 * Math.PI / 2) {
|
||||||
|
return a + Math.PI;
|
||||||
|
} else {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
source = new Bokeh.ColumnDataSource({
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
values: values,
|
||||||
|
percentages: normalized_values.map((function(_this) {
|
||||||
|
return function(v) {
|
||||||
|
return sprintf("%.2f%%", v * 100);
|
||||||
|
};
|
||||||
|
})(this)),
|
||||||
|
start_angles: start_angles,
|
||||||
|
end_angles: end_angles,
|
||||||
|
text_angles: text_angles,
|
||||||
|
colors: colors,
|
||||||
|
text_colors: text_colors,
|
||||||
|
text_cx: text_cx,
|
||||||
|
text_cy: text_cy
|
||||||
|
}
|
||||||
|
});
|
||||||
|
g1 = new models.AnnularWedge({
|
||||||
|
x: cx,
|
||||||
|
y: cy,
|
||||||
|
inner_radius: inner_radius,
|
||||||
|
outer_radius: outer_radius,
|
||||||
|
start_angle: {
|
||||||
|
field: "start_angles"
|
||||||
|
},
|
||||||
|
end_angle: {
|
||||||
|
field: "end_angles"
|
||||||
|
},
|
||||||
|
line_color: null,
|
||||||
|
line_width: 1,
|
||||||
|
fill_color: {
|
||||||
|
field: "colors"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
h1 = new models.AnnularWedge({
|
||||||
|
x: cx,
|
||||||
|
y: cy,
|
||||||
|
inner_radius: inner_radius,
|
||||||
|
outer_radius: outer_radius,
|
||||||
|
start_angle: {
|
||||||
|
field: "start_angles"
|
||||||
|
},
|
||||||
|
end_angle: {
|
||||||
|
field: "end_angles"
|
||||||
|
},
|
||||||
|
line_color: null,
|
||||||
|
line_width: 1,
|
||||||
|
fill_color: {
|
||||||
|
field: "colors"
|
||||||
|
},
|
||||||
|
fill_alpha: 0.8
|
||||||
|
});
|
||||||
|
r1 = new models.GlyphRenderer({
|
||||||
|
data_source: source,
|
||||||
|
glyph: g1,
|
||||||
|
hover_glyph: h1
|
||||||
|
});
|
||||||
|
g2 = new models.Text({
|
||||||
|
x: {
|
||||||
|
field: "text_cx"
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
field: "text_cy"
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
field: (ref7 = opts.slice_labels) != null ? ref7 : "labels"
|
||||||
|
},
|
||||||
|
angle: {
|
||||||
|
field: "text_angles"
|
||||||
|
},
|
||||||
|
text_align: "center",
|
||||||
|
text_baseline: "middle",
|
||||||
|
text_color: {
|
||||||
|
field: "text_colors"
|
||||||
|
},
|
||||||
|
text_font_size: "9pt"
|
||||||
|
});
|
||||||
|
r2 = new models.GlyphRenderer({
|
||||||
|
data_source: source,
|
||||||
|
glyph: g2
|
||||||
|
});
|
||||||
|
xdr = new models.DataRange1d({
|
||||||
|
renderers: [r1],
|
||||||
|
range_padding: 0.2
|
||||||
|
});
|
||||||
|
ydr = new models.DataRange1d({
|
||||||
|
renderers: [r1],
|
||||||
|
range_padding: 0.2
|
||||||
|
});
|
||||||
|
plot = new models.Plot({
|
||||||
|
x_range: xdr,
|
||||||
|
y_range: ydr
|
||||||
|
});
|
||||||
|
if (opts.width != null) {
|
||||||
|
plot.plot_width = opts.width;
|
||||||
|
}
|
||||||
|
if (opts.height != null) {
|
||||||
|
plot.plot_height = opts.height;
|
||||||
|
}
|
||||||
|
plot.add_renderers(r1, r2);
|
||||||
|
tooltip = "<div>@labels</div><div><b>@values</b> (@percentages)</div>";
|
||||||
|
hover = new models.HoverTool({
|
||||||
|
renderers: [r1],
|
||||||
|
tooltips: tooltip
|
||||||
|
});
|
||||||
|
plot.add_tools(hover);
|
||||||
|
return plot;
|
||||||
|
};
|
||||||
|
|
||||||
|
bar = function(data, opts) {
|
||||||
|
var anchor, attachment, bottom, column_names, columns, dy, g1, hover, i, j, k, label, labels, left, len, len1, len2, len3, len4, m, n, name, o, orientation, p, palette, plot, q, r, r1, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, renderers, right, row, rows, s, source, stacked, tooltip, top, v, xaxis, xdr, xformatter, yaxis, ydr;
|
||||||
|
if (opts == null) {
|
||||||
|
opts = {};
|
||||||
|
}
|
||||||
|
column_names = data[0];
|
||||||
|
rows = data.slice(1);
|
||||||
|
columns = (function() {
|
||||||
|
var k, len, results;
|
||||||
|
results = [];
|
||||||
|
for (k = 0, len = column_names.length; k < len; k++) {
|
||||||
|
name = column_names[k];
|
||||||
|
results.push([]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
for (k = 0, len = rows.length; k < len; k++) {
|
||||||
|
row = rows[k];
|
||||||
|
for (i = m = 0, len1 = row.length; m < len1; i = ++m) {
|
||||||
|
v = row[i];
|
||||||
|
columns[i].push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labels = _.map(columns[0], function(v) {
|
||||||
|
return v.toString();
|
||||||
|
});
|
||||||
|
columns = columns.slice(1);
|
||||||
|
yaxis = new models.CategoricalAxis();
|
||||||
|
ydr = new models.FactorRange({
|
||||||
|
factors: labels
|
||||||
|
});
|
||||||
|
if (opts.axis_number_format != null) {
|
||||||
|
xformatter = new models.NumeralTickFormatter({
|
||||||
|
format: opts.axis_number_format
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
xformatter = new models.BasicTickFormatter();
|
||||||
|
}
|
||||||
|
xaxis = new models.LinearAxis({
|
||||||
|
formatter: xformatter
|
||||||
|
});
|
||||||
|
xdr = new models.DataRange1d({
|
||||||
|
start: 0
|
||||||
|
});
|
||||||
|
if (_.isArray(opts.palette)) {
|
||||||
|
palette = opts.palette;
|
||||||
|
} else {
|
||||||
|
palette = palettes[(ref = opts.palette) != null ? ref : "Spectral11"].map(num2hexcolor);
|
||||||
|
}
|
||||||
|
stacked = (ref1 = opts.stacked) != null ? ref1 : false;
|
||||||
|
orientation = (ref2 = opts.orientation) != null ? ref2 : "horizontal";
|
||||||
|
renderers = [];
|
||||||
|
if (stacked) {
|
||||||
|
left = [];
|
||||||
|
right = [];
|
||||||
|
for (i = n = 0, ref3 = columns.length; 0 <= ref3 ? n < ref3 : n > ref3; i = 0 <= ref3 ? ++n : --n) {
|
||||||
|
bottom = [];
|
||||||
|
top = [];
|
||||||
|
for (j = o = 0, len2 = labels.length; o < len2; j = ++o) {
|
||||||
|
label = labels[j];
|
||||||
|
if (i === 0) {
|
||||||
|
left.push(0);
|
||||||
|
right.push(columns[i][j]);
|
||||||
|
} else {
|
||||||
|
left[j] += columns[i - 1][j];
|
||||||
|
right[j] += columns[i][j];
|
||||||
|
}
|
||||||
|
bottom.push(label + ":0");
|
||||||
|
top.push(label + ":1");
|
||||||
|
}
|
||||||
|
source = new Bokeh.ColumnDataSource({
|
||||||
|
data: {
|
||||||
|
left: _.clone(left),
|
||||||
|
right: _.clone(right),
|
||||||
|
top: top,
|
||||||
|
bottom: bottom,
|
||||||
|
labels: labels,
|
||||||
|
values: columns[i],
|
||||||
|
columns: (function() {
|
||||||
|
var len3, p, ref4, results;
|
||||||
|
ref4 = columns[i];
|
||||||
|
results = [];
|
||||||
|
for (p = 0, len3 = ref4.length; p < len3; p++) {
|
||||||
|
v = ref4[p];
|
||||||
|
results.push(column_names[i + 1]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
g1 = new models.Quad({
|
||||||
|
left: {
|
||||||
|
field: "left"
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
field: "bottom"
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
field: "right"
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
field: "top"
|
||||||
|
},
|
||||||
|
line_color: null,
|
||||||
|
fill_color: palette[i % palette.length]
|
||||||
|
});
|
||||||
|
r1 = new models.GlyphRenderer({
|
||||||
|
data_source: source,
|
||||||
|
glyph: g1
|
||||||
|
});
|
||||||
|
renderers.push(r1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dy = 1 / columns.length;
|
||||||
|
for (i = p = 0, ref4 = columns.length; 0 <= ref4 ? p < ref4 : p > ref4; i = 0 <= ref4 ? ++p : --p) {
|
||||||
|
left = [];
|
||||||
|
right = [];
|
||||||
|
bottom = [];
|
||||||
|
top = [];
|
||||||
|
for (j = q = 0, len3 = labels.length; q < len3; j = ++q) {
|
||||||
|
label = labels[j];
|
||||||
|
left.push(0);
|
||||||
|
right.push(columns[i][j]);
|
||||||
|
bottom.push(label + ":" + (i * dy));
|
||||||
|
top.push(label + ":" + ((i + 1) * dy));
|
||||||
|
}
|
||||||
|
source = new Bokeh.ColumnDataSource({
|
||||||
|
data: {
|
||||||
|
left: left,
|
||||||
|
right: right,
|
||||||
|
top: top,
|
||||||
|
bottom: bottom,
|
||||||
|
labels: labels,
|
||||||
|
values: columns[i],
|
||||||
|
columns: (function() {
|
||||||
|
var len4, ref5, results, s;
|
||||||
|
ref5 = columns[i];
|
||||||
|
results = [];
|
||||||
|
for (s = 0, len4 = ref5.length; s < len4; s++) {
|
||||||
|
v = ref5[s];
|
||||||
|
results.push(column_names[i + 1]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
g1 = new models.Quad({
|
||||||
|
left: {
|
||||||
|
field: "left"
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
field: "bottom"
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
field: "right"
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
field: "top"
|
||||||
|
},
|
||||||
|
line_color: null,
|
||||||
|
fill_color: palette[i % palette.length]
|
||||||
|
});
|
||||||
|
r1 = new models.GlyphRenderer({
|
||||||
|
data_source: source,
|
||||||
|
glyph: g1
|
||||||
|
});
|
||||||
|
renderers.push(r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (orientation === "vertical") {
|
||||||
|
ref5 = [ydr, xdr], xdr = ref5[0], ydr = ref5[1];
|
||||||
|
ref6 = [yaxis, xaxis], xaxis = ref6[0], yaxis = ref6[1];
|
||||||
|
for (s = 0, len4 = renderers.length; s < len4; s++) {
|
||||||
|
r = renderers[s];
|
||||||
|
data = r.data_source.data;
|
||||||
|
ref7 = [data.bottom, data.left], data.left = ref7[0], data.bottom = ref7[1];
|
||||||
|
ref8 = [data.top, data.right], data.right = ref8[0], data.top = ref8[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plot = new models.Plot({
|
||||||
|
x_range: xdr,
|
||||||
|
y_range: ydr
|
||||||
|
});
|
||||||
|
if (opts.width != null) {
|
||||||
|
plot.plot_width = opts.width;
|
||||||
|
}
|
||||||
|
if (opts.height != null) {
|
||||||
|
plot.plot_height = opts.height;
|
||||||
|
}
|
||||||
|
plot.add_renderers.apply(plot, renderers);
|
||||||
|
plot.add_layout(yaxis, "left");
|
||||||
|
plot.add_layout(xaxis, "below");
|
||||||
|
tooltip = "<div>@labels</div><div>@columns: <b>@values</b></div>";
|
||||||
|
if (orientation === "horizontal") {
|
||||||
|
anchor = "right_center";
|
||||||
|
attachment = "horizontal";
|
||||||
|
} else {
|
||||||
|
anchor = "top_center";
|
||||||
|
attachment = "vertical";
|
||||||
|
}
|
||||||
|
hover = new models.HoverTool({
|
||||||
|
renderers: renderers,
|
||||||
|
tooltips: tooltip,
|
||||||
|
point_policy: "snap_to_data",
|
||||||
|
anchor: anchor,
|
||||||
|
attachment: attachment,
|
||||||
|
show_arrow: opts.show_arrow
|
||||||
|
});
|
||||||
|
plot.add_tools(hover);
|
||||||
|
return plot;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
pie: pie,
|
||||||
|
bar: bar
|
||||||
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
"use strict";
|
||||||
|
function transpose(array) {
|
||||||
|
var rows = array.length;
|
||||||
|
var cols = array[0].length;
|
||||||
|
var transposed = [];
|
||||||
|
for (var j = 0; j < cols; j++) {
|
||||||
|
transposed[j] = [];
|
||||||
|
for (var i = 0; i < rows; i++) {
|
||||||
|
transposed[j][i] = array[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transposed;
|
||||||
|
}
|
||||||
|
exports.transpose = transpose;
|
||||||
|
function linspace(start, stop, num) {
|
||||||
|
if (num === void 0) { num = 100; }
|
||||||
|
var step = (stop - start) / (num - 1);
|
||||||
|
var array = new Array(num);
|
||||||
|
for (var i = 0; i < num; i++) {
|
||||||
|
array[i] = start + step * i;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
exports.linspace = linspace;
|
||||||
|
function arange(start, stop, step) {
|
||||||
|
if (step === void 0) { step = 1; }
|
||||||
|
var num = Math.ceil((stop - start) / step);
|
||||||
|
var array = new Array(num);
|
||||||
|
for (var i = 0; i < num; i++) {
|
||||||
|
array[i] = start + step * i;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
exports.arange = arange;
|
|
@ -0,0 +1,118 @@
|
||||||
|
module.exports = {
|
||||||
|
Arrow: require("../models/annotations/arrow").Model,
|
||||||
|
OpenHead: require("../models/annotations/arrow_head").OpenHead,
|
||||||
|
NormalHead: require("../models/annotations/arrow_head").NormalHead,
|
||||||
|
VeeHead: require("../models/annotations/arrow_head").VeeHead,
|
||||||
|
BoxAnnotation: require("../models/annotations/box_annotation").Model,
|
||||||
|
ColorBar: require("../models/annotations/color_bar").Model,
|
||||||
|
Label: require("../models/annotations/label").Model,
|
||||||
|
LabelSet: require("../models/annotations/label_set").Model,
|
||||||
|
Legend: require("../models/annotations/legend").Model,
|
||||||
|
PolyAnnotation: require("../models/annotations/poly_annotation").Model,
|
||||||
|
Span: require("../models/annotations/span").Model,
|
||||||
|
Title: require("../models/annotations/title").Model,
|
||||||
|
Tooltip: require("../models/annotations/tooltip").Model,
|
||||||
|
Axis: require("../models/axes/axis").Model,
|
||||||
|
ContinuousAxis: require("../models/axes/continuous_axis").Model,
|
||||||
|
LinearAxis: require("../models/axes/linear_axis").Model,
|
||||||
|
LogAxis: require("../models/axes/log_axis").Model,
|
||||||
|
CategoricalAxis: require("../models/axes/categorical_axis").Model,
|
||||||
|
DatetimeAxis: require("../models/axes/datetime_axis").Model,
|
||||||
|
OpenURL: require("../models/callbacks/open_url").Model,
|
||||||
|
CustomJS: require("../models/callbacks/customjs").Model,
|
||||||
|
TickFormatter: require("../models/formatters/tick_formatter").Model,
|
||||||
|
BasicTickFormatter: require("../models/formatters/basic_tick_formatter").Model,
|
||||||
|
LogTickFormatter: require("../models/formatters/basic_tick_formatter").Model,
|
||||||
|
CategoricalTickFormatter: require("../models/formatters/categorical_tick_formatter").Model,
|
||||||
|
DatetimeTickFormatter: require("../models/formatters/datetime_tick_formatter").Model,
|
||||||
|
FuncTickFormatter: require("../models/formatters/func_tick_formatter").Model,
|
||||||
|
NumeralTickFormatter: require("../models/formatters/numeral_tick_formatter").Model,
|
||||||
|
PrintfTickFormatter: require("../models/formatters/printf_tick_formatter").Model,
|
||||||
|
Glyph: require("../models/glyphs/glyph").Model,
|
||||||
|
AnnularWedge: require("../models/glyphs/annular_wedge").Model,
|
||||||
|
Annulus: require("../models/glyphs/annulus").Model,
|
||||||
|
Arc: require("../models/glyphs/arc").Model,
|
||||||
|
Bezier: require("../models/glyphs/bezier").Model,
|
||||||
|
Circle: require("../models/glyphs/circle").Model,
|
||||||
|
Ellipse: require("../models/glyphs/ellipse").Model,
|
||||||
|
ImageRGBA: require("../models/glyphs/image_rgba").Model,
|
||||||
|
Image: require("../models/glyphs/image").Model,
|
||||||
|
ImageURL: require("../models/glyphs/image_url").Model,
|
||||||
|
Line: require("../models/glyphs/line").Model,
|
||||||
|
MultiLine: require("../models/glyphs/multi_line").Model,
|
||||||
|
Oval: require("../models/glyphs/oval").Model,
|
||||||
|
Patch: require("../models/glyphs/patch").Model,
|
||||||
|
Patches: require("../models/glyphs/patches").Model,
|
||||||
|
Quad: require("../models/glyphs/quad").Model,
|
||||||
|
Quadratic: require("../models/glyphs/quadratic").Model,
|
||||||
|
Ray: require("../models/glyphs/ray").Model,
|
||||||
|
Rect: require("../models/glyphs/rect").Model,
|
||||||
|
Segment: require("../models/glyphs/segment").Model,
|
||||||
|
Text: require("../models/glyphs/text").Model,
|
||||||
|
Wedge: require("../models/glyphs/wedge").Model,
|
||||||
|
Gear: require("../models/glyphs/gear").Model,
|
||||||
|
Grid: require("../models/grids/grid").Model,
|
||||||
|
ImageSource: require("../models/tiles/image_source").Model,
|
||||||
|
LayoutDOM: require("../models/layouts/layout_dom").Model,
|
||||||
|
Row: require("../models/layouts/row").Model,
|
||||||
|
Column: require("../models/layouts/column").Model,
|
||||||
|
Spacer: require("../models/layouts/spacer").Model,
|
||||||
|
WidgetBox: require("../models/layouts/widget_box").Model,
|
||||||
|
GMapPlot: require("../models/plots/gmap_plot").Model,
|
||||||
|
LinearColorMapper: require("../models/mappers/linear_color_mapper").Model,
|
||||||
|
markers: [require('../models/markers/index')],
|
||||||
|
Model: require("../model").Model,
|
||||||
|
Plot: require("../models/plots/plot").Model,
|
||||||
|
Range: require("../models/ranges/range").Model,
|
||||||
|
Range1d: require("../models/ranges/range1d").Model,
|
||||||
|
DataRange: require("../models/ranges/data_range").Model,
|
||||||
|
DataRange1d: require("../models/ranges/data_range1d").Model,
|
||||||
|
FactorRange: require("../models/ranges/factor_range").Model,
|
||||||
|
Renderer: require("../models/renderers/renderer").Model,
|
||||||
|
TileRenderer: require("../models/tiles/tile_renderer").Model,
|
||||||
|
DynamicImageRenderer: require("../models/tiles/dynamic_image_renderer").Model,
|
||||||
|
GlyphRenderer: require("../models/renderers/glyph_renderer").Model,
|
||||||
|
GuideRenderer: require("../models/renderers/guide_renderer").Model,
|
||||||
|
DataSource: require("../models/sources/data_source").Model,
|
||||||
|
ColumnDataSource: require("../models/sources/column_data_source").Model,
|
||||||
|
AjaxDataSource: require("../models/sources/ajax_data_source").Model,
|
||||||
|
Ticker: require("../models/tickers/ticker").Model,
|
||||||
|
ContinuousTicker: require("../models/tickers/continuous_ticker").Model,
|
||||||
|
FixedTicker: require("../models/tickers/fixed_ticker").Model,
|
||||||
|
AdaptiveTicker: require("../models/tickers/adaptive_ticker").Model,
|
||||||
|
CompositeTicker: require("../models/tickers/composite_ticker").Model,
|
||||||
|
SingleIntervalTicker: require("../models/tickers/single_interval_ticker").Model,
|
||||||
|
DaysTicker: require("../models/tickers/days_ticker").Model,
|
||||||
|
MonthsTicker: require("../models/tickers/months_ticker").Model,
|
||||||
|
YearsTicker: require("../models/tickers/years_ticker").Model,
|
||||||
|
BasicTicker: require("../models/tickers/basic_ticker").Model,
|
||||||
|
LogTicker: require("../models/tickers/log_ticker").Model,
|
||||||
|
CategoricalTicker: require("../models/tickers/categorical_ticker").Model,
|
||||||
|
DatetimeTicker: require("../models/tickers/datetime_ticker").Model,
|
||||||
|
TileSource: require("../models/tiles/tile_source").Model,
|
||||||
|
MercatorTileSource: require("../models/tiles/mercator_tile_source").Model,
|
||||||
|
TMSTileSource: require("../models/tiles/tms_tile_source").Model,
|
||||||
|
WMTSTileSource: require("../models/tiles/wmts_tile_source").Model,
|
||||||
|
QUADKEYTileSource: require("../models/tiles/quadkey_tile_source").Model,
|
||||||
|
BBoxTileSource: require("../models/tiles/bbox_tile_source").Model,
|
||||||
|
ToolbarBase: require("../models/tools/toolbar_base").Model,
|
||||||
|
Toolbar: require("../models/tools/toolbar").Model,
|
||||||
|
ToolbarBox: require("../models/tools/toolbar_box").Model,
|
||||||
|
ToolEvents: require("../common/tool_events").Model,
|
||||||
|
Tool: require("../models/tools/tool").Model,
|
||||||
|
PanTool: require("../models/tools/gestures/pan_tool").Model,
|
||||||
|
WheelZoomTool: require("../models/tools/gestures/wheel_zoom_tool").Model,
|
||||||
|
SaveTool: require("../models/tools/actions/save_tool").Model,
|
||||||
|
UndoTool: require("../models/tools/actions/undo_tool").Model,
|
||||||
|
RedoTool: require("../models/tools/actions/redo_tool").Model,
|
||||||
|
ResetTool: require("../models/tools/actions/reset_tool").Model,
|
||||||
|
ResizeTool: require("../models/tools/gestures/resize_tool").Model,
|
||||||
|
CrosshairTool: require("../models/tools/inspectors/crosshair_tool").Model,
|
||||||
|
BoxZoomTool: require("../models/tools/gestures/box_zoom_tool").Model,
|
||||||
|
BoxSelectTool: require("../models/tools/gestures/box_select_tool").Model,
|
||||||
|
LassoSelectTool: require("../models/tools/gestures/lasso_select_tool").Model,
|
||||||
|
PolySelectTool: require("../models/tools/gestures/poly_select_tool").Model,
|
||||||
|
TapTool: require("../models/tools/gestures/tap_tool").Model,
|
||||||
|
HoverTool: require("../models/tools/inspectors/hover_tool").Model,
|
||||||
|
HelpTool: require("../models/tools/actions/help_tool").Model
|
||||||
|
};
|
|
@ -0,0 +1,889 @@
|
||||||
|
var $, BOKEH_ROOT, Document, Figure, _, _default_tools, _default_tooltips, _known_tools, _with_default, color, embed, figure, gridplot, models, show, sprintf,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty,
|
||||||
|
slice = [].slice;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
sprintf = require("sprintf");
|
||||||
|
|
||||||
|
Document = require("../document").Document;
|
||||||
|
|
||||||
|
embed = require("../embed");
|
||||||
|
|
||||||
|
BOKEH_ROOT = require("../embed").BOKEH_ROOT;
|
||||||
|
|
||||||
|
models = require("./models");
|
||||||
|
|
||||||
|
_default_tooltips = [["index", "$index"], ["data (x, y)", "($x, $y)"], ["canvas (x, y)", "($sx, $sy)"]];
|
||||||
|
|
||||||
|
_default_tools = "pan,wheel_zoom,box_zoom,save,reset,help";
|
||||||
|
|
||||||
|
_known_tools = {
|
||||||
|
pan: function(plot) {
|
||||||
|
return new models.PanTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["width", "height"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
xpan: function(plot) {
|
||||||
|
return new models.PanTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["width"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ypan: function(plot) {
|
||||||
|
return new models.PanTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["height"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
wheel_zoom: function(plot) {
|
||||||
|
return new models.WheelZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["width", "height"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
xwheel_zoom: function(plot) {
|
||||||
|
return new models.WheelZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["width"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ywheel_zoom: function(plot) {
|
||||||
|
return new models.WheelZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ["height"]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resize: function(plot) {
|
||||||
|
return new models.ResizeTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
click: function(plot) {
|
||||||
|
return new models.TapTool({
|
||||||
|
plot: plot,
|
||||||
|
behavior: "inspect"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
tap: function(plot) {
|
||||||
|
return new models.TapTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
crosshair: function(plot) {
|
||||||
|
return new models.CrosshairTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
box_select: function(plot) {
|
||||||
|
return new models.BoxSelectTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
xbox_select: function(plot) {
|
||||||
|
return new models.BoxSelectTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ['width']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ybox_select: function(plot) {
|
||||||
|
return new models.BoxSelectTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ['height']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
poly_select: function(plot) {
|
||||||
|
return new models.PolySelectTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
lasso_select: function(plot) {
|
||||||
|
return new models.LassoSelectTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
box_zoom: function(plot) {
|
||||||
|
return new models.BoxZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ['width', 'height']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
xbox_zoom: function(plot) {
|
||||||
|
return new models.BoxZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ['width']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ybox_zoom: function(plot) {
|
||||||
|
return new models.BoxZoomTool({
|
||||||
|
plot: plot,
|
||||||
|
dimensions: ['height']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
hover: function(plot) {
|
||||||
|
return new models.HoverTool({
|
||||||
|
plot: plot,
|
||||||
|
tooltips: _default_tooltips
|
||||||
|
});
|
||||||
|
},
|
||||||
|
save: function(plot) {
|
||||||
|
return new models.SaveTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
previewsave: function(plot) {
|
||||||
|
return new models.SaveTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
undo: function(plot) {
|
||||||
|
return new models.UndoTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
redo: function(plot) {
|
||||||
|
return new models.RedoTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
reset: function(plot) {
|
||||||
|
return new models.ResetTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
},
|
||||||
|
help: function(plot) {
|
||||||
|
return new models.HelpTool({
|
||||||
|
plot: plot
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_with_default = function(value, default_value) {
|
||||||
|
if (value === void 0) {
|
||||||
|
return default_value;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure = (function(superClass) {
|
||||||
|
extend(Figure, superClass);
|
||||||
|
|
||||||
|
function Figure(attributes, options) {
|
||||||
|
var attrs, ref, ref1, ref2, ref3, ref4, ref5, tools, x_axis_label, x_axis_location, x_axis_type, x_minor_ticks, y_axis_label, y_axis_location, y_axis_type, y_minor_ticks;
|
||||||
|
if (attributes == null) {
|
||||||
|
attributes = {};
|
||||||
|
}
|
||||||
|
if (options == null) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
attrs = _.clone(attributes);
|
||||||
|
tools = _with_default(attrs.tools, _default_tools);
|
||||||
|
delete attrs.tools;
|
||||||
|
attrs.x_range = this._get_range(attrs.x_range);
|
||||||
|
attrs.y_range = this._get_range(attrs.y_range);
|
||||||
|
x_axis_type = _.isUndefined(attrs.x_axis_type) ? "auto" : attrs.x_axis_type;
|
||||||
|
y_axis_type = _.isUndefined(attrs.y_axis_type) ? "auto" : attrs.y_axis_type;
|
||||||
|
delete attrs.x_axis_type;
|
||||||
|
delete attrs.y_axis_type;
|
||||||
|
x_minor_ticks = (ref = attrs.x_minor_ticks) != null ? ref : "auto";
|
||||||
|
y_minor_ticks = (ref1 = attrs.y_minor_ticks) != null ? ref1 : "auto";
|
||||||
|
delete attrs.x_minor_ticks;
|
||||||
|
delete attrs.y_minor_ticks;
|
||||||
|
x_axis_location = (ref2 = attrs.x_axis_location) != null ? ref2 : "below";
|
||||||
|
y_axis_location = (ref3 = attrs.y_axis_location) != null ? ref3 : "left";
|
||||||
|
delete attrs.x_axis_location;
|
||||||
|
delete attrs.y_axis_location;
|
||||||
|
x_axis_label = (ref4 = attrs.x_axis_label) != null ? ref4 : "";
|
||||||
|
y_axis_label = (ref5 = attrs.y_axis_label) != null ? ref5 : "";
|
||||||
|
delete attrs.x_axis_label;
|
||||||
|
delete attrs.y_axis_label;
|
||||||
|
if (!_.isUndefined(attrs.width)) {
|
||||||
|
if (_.isUndefined(attrs.plot_width)) {
|
||||||
|
attrs.plot_width = attrs.width;
|
||||||
|
} else {
|
||||||
|
throw new Error("both 'width' and 'plot_width' can't be given at the same time");
|
||||||
|
}
|
||||||
|
delete attrs.width;
|
||||||
|
}
|
||||||
|
if (!_.isUndefined(attrs.height)) {
|
||||||
|
if (_.isUndefined(attrs.plot_height)) {
|
||||||
|
attrs.plot_height = attrs.height;
|
||||||
|
} else {
|
||||||
|
throw new Error("both 'height' and 'plot_height' can't be given at the same time");
|
||||||
|
}
|
||||||
|
delete attrs.height;
|
||||||
|
}
|
||||||
|
Figure.__super__.constructor.call(this, attrs, options);
|
||||||
|
this._process_guides(0, x_axis_type, x_axis_location, x_minor_ticks, x_axis_label);
|
||||||
|
this._process_guides(1, y_axis_type, y_axis_location, y_minor_ticks, y_axis_label);
|
||||||
|
this.add_tools.apply(this, this._process_tools(tools));
|
||||||
|
this._legend = new models.Legend({
|
||||||
|
plot: this
|
||||||
|
});
|
||||||
|
this.add_renderers(this._legend);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(Figure.prototype, "xgrid", {
|
||||||
|
get: function() {
|
||||||
|
return this.renderers.filter(function(r) {
|
||||||
|
return r instanceof models.Grid && r.dimension === 0;
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Figure.prototype, "ygrid", {
|
||||||
|
get: function() {
|
||||||
|
return this.renderers.filter(function(r) {
|
||||||
|
return r instanceof models.Grid && r.dimension === 1;
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Figure.prototype, "xaxis", {
|
||||||
|
get: function() {
|
||||||
|
return this.below.concat(this.above).filter(function(r) {
|
||||||
|
return r instanceof models.Axis;
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Figure.prototype, "yaxis", {
|
||||||
|
get: function() {
|
||||||
|
return this.left.concat(this.right).filter(function(r) {
|
||||||
|
return r instanceof models.Axis;
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Figure.prototype.annular_wedge = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.AnnularWedge, "x,y,inner_radius,outer_radius,start_angle,end_angle", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.annulus = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Annulus, "x,y,inner_radius,outer_radius", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.arc = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Arc, "x,y,radius,start_angle,end_angle", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.bezier = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Bezier, "x0,y0,x1,y1,cx0,cy0,cx1,cy1", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.ellipse = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Ellipse, "x,y,width,height", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.gear = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Gear, "x,y,module,teeth", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.image = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Image, "color_mapper,image,rows,cols,x,y,dw,dh", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.image_rgba = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.ImageRGBA, "image,rows,cols,x,y,dw,dh", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.image_url = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.ImageURL, "url,x,y,w,h", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.line = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Line, "x,y", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.multi_line = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.MultiLine, "xs,ys", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.oval = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Oval, "x,y,width,height", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.patch = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Patch, "x,y", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.patches = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Patches, "xs,ys", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.quad = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Quad, "left,right,bottom,top", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.quadratic = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Quadratic, "x0,y0,x1,y1,cx,cy", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.ray = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Ray, "x,y,length", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.rect = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Rect, "x,y,width,height", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.segment = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Segment, "x0,y0,x1,y1", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.text = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Text, "x,y,text", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.wedge = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._glyph(models.Wedge, "x,y,radius,start_angle,end_angle", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.asterisk = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Asterisk, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.circle = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Circle, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.circle_cross = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.CircleCross, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.circle_x = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.CircleX, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.cross = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Cross, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.diamond = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Diamond, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.diamond_cross = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.DiamondCross, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.inverted_triangle = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.InvertedTriangle, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.square = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Square, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.square_cross = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.SquareCross, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.square_x = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.SquareX, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.triangle = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.Triangle, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype.x = function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this._marker(models.X, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._vectorable = ["fill_color", "fill_alpha", "line_color", "line_alpha", "line_width", "text_color", "text_alpha", "text_font_size"];
|
||||||
|
|
||||||
|
Figure.prototype._default_color = "#1f77b4";
|
||||||
|
|
||||||
|
Figure.prototype._default_alpha = 1.0;
|
||||||
|
|
||||||
|
Figure.prototype._pop_colors_and_alpha = function(cls, attrs, prefix, default_color, default_alpha) {
|
||||||
|
var _update_with, alpha, color, result;
|
||||||
|
if (prefix == null) {
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
if (default_color == null) {
|
||||||
|
default_color = this._default_color;
|
||||||
|
}
|
||||||
|
if (default_alpha == null) {
|
||||||
|
default_alpha = this._default_alpha;
|
||||||
|
}
|
||||||
|
result = {};
|
||||||
|
color = _with_default(attrs[prefix + "color"], default_color);
|
||||||
|
alpha = _with_default(attrs[prefix + "alpha"], default_alpha);
|
||||||
|
delete attrs[prefix + "color"];
|
||||||
|
delete attrs[prefix + "alpha"];
|
||||||
|
_update_with = function(name, default_value) {
|
||||||
|
if (cls.prototype.props[name] != null) {
|
||||||
|
result[name] = _with_default(attrs[prefix + name], default_value);
|
||||||
|
return delete attrs[prefix + name];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_update_with("fill_color", color);
|
||||||
|
_update_with("line_color", color);
|
||||||
|
_update_with("text_color", "black");
|
||||||
|
_update_with("fill_alpha", alpha);
|
||||||
|
_update_with("line_alpha", alpha);
|
||||||
|
_update_with("text_alpha", alpha);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._find_uniq_name = function(data, name) {
|
||||||
|
var i, new_name;
|
||||||
|
i = 1;
|
||||||
|
while (true) {
|
||||||
|
new_name = name + "__" + i;
|
||||||
|
if (data[new_name] != null) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._fixup_values = function(cls, data, attrs) {
|
||||||
|
var name, results, value;
|
||||||
|
results = [];
|
||||||
|
for (name in attrs) {
|
||||||
|
value = attrs[name];
|
||||||
|
results.push((function(_this) {
|
||||||
|
return function(name, value) {
|
||||||
|
var field, prop;
|
||||||
|
prop = cls.prototype.props[name];
|
||||||
|
if (prop != null) {
|
||||||
|
if (prop.type.prototype.dataspec) {
|
||||||
|
if (value != null) {
|
||||||
|
if (_.isArray(value)) {
|
||||||
|
if (data[name] != null) {
|
||||||
|
if (data[name] !== value) {
|
||||||
|
field = _this._find_uniq_name(data, name);
|
||||||
|
data[field] = value;
|
||||||
|
} else {
|
||||||
|
field = name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field = name;
|
||||||
|
data[field] = value;
|
||||||
|
}
|
||||||
|
return attrs[name] = {
|
||||||
|
field: field
|
||||||
|
};
|
||||||
|
} else if (_.isNumber(value) || _.isString(value)) {
|
||||||
|
return attrs[name] = {
|
||||||
|
value: value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this)(name, value));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._glyph = function(cls, params, args) {
|
||||||
|
var _make_glyph, attrs, data, fn, glyph, glyph_ca, glyph_renderer, has_hglyph, has_sglyph, hglyph, hglyph_ca, i, j, k, legend, len, nsglyph, nsglyph_ca, opts, param, ref, ref1, sglyph, sglyph_ca, source;
|
||||||
|
params = params.split(",");
|
||||||
|
if (args.length === 1) {
|
||||||
|
attrs = args[0];
|
||||||
|
attrs = _.clone(attrs);
|
||||||
|
} else {
|
||||||
|
ref = args, args = 2 <= ref.length ? slice.call(ref, 0, j = ref.length - 1) : (j = 0, []), opts = ref[j++];
|
||||||
|
attrs = _.clone(opts);
|
||||||
|
fn = function(param, i) {
|
||||||
|
return attrs[param] = args[i];
|
||||||
|
};
|
||||||
|
for (i = k = 0, len = params.length; k < len; i = ++k) {
|
||||||
|
param = params[i];
|
||||||
|
fn(param, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legend = attrs.legend;
|
||||||
|
delete attrs.legend;
|
||||||
|
has_sglyph = _.any(_.keys(attrs), function(key) {
|
||||||
|
return key.startsWith("selection_");
|
||||||
|
});
|
||||||
|
has_hglyph = _.any(_.keys(attrs), function(key) {
|
||||||
|
return key.startsWith("hover_");
|
||||||
|
});
|
||||||
|
glyph_ca = this._pop_colors_and_alpha(cls, attrs);
|
||||||
|
nsglyph_ca = this._pop_colors_and_alpha(cls, attrs, "nonselection_", void 0, 0.1);
|
||||||
|
sglyph_ca = has_sglyph ? this._pop_colors_and_alpha(cls, attrs, "selection_") : {};
|
||||||
|
hglyph_ca = has_hglyph ? this._pop_colors_and_alpha(cls, attrs, "hover_") : {};
|
||||||
|
source = (ref1 = attrs.source) != null ? ref1 : new models.ColumnDataSource();
|
||||||
|
data = _.clone(source.data);
|
||||||
|
delete attrs.source;
|
||||||
|
this._fixup_values(cls, data, glyph_ca);
|
||||||
|
this._fixup_values(cls, data, nsglyph_ca);
|
||||||
|
this._fixup_values(cls, data, sglyph_ca);
|
||||||
|
this._fixup_values(cls, data, hglyph_ca);
|
||||||
|
this._fixup_values(cls, data, attrs);
|
||||||
|
source.data = data;
|
||||||
|
_make_glyph = (function(_this) {
|
||||||
|
return function(cls, attrs, extra_attrs) {
|
||||||
|
return new cls(_.extend({}, attrs, extra_attrs));
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
glyph = _make_glyph(cls, attrs, glyph_ca);
|
||||||
|
nsglyph = _make_glyph(cls, attrs, nsglyph_ca);
|
||||||
|
sglyph = has_sglyph ? _make_glyph(cls, attrs, sglyph_ca) : null;
|
||||||
|
hglyph = has_hglyph ? _make_glyph(cls, attrs, hglyph_ca) : null;
|
||||||
|
glyph_renderer = new models.GlyphRenderer({
|
||||||
|
data_source: source,
|
||||||
|
glyph: glyph,
|
||||||
|
nonselection_glyph: nsglyph,
|
||||||
|
selection_glyph: sglyph,
|
||||||
|
hover_glyph: hglyph
|
||||||
|
});
|
||||||
|
if (legend != null) {
|
||||||
|
this._update_legend(legend, glyph_renderer);
|
||||||
|
}
|
||||||
|
this.add_renderers(glyph_renderer);
|
||||||
|
return glyph_renderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._marker = function(cls, args) {
|
||||||
|
return this._glyph(cls, "x,y", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._get_range = function(range) {
|
||||||
|
if (range == null) {
|
||||||
|
return new models.DataRange1d();
|
||||||
|
}
|
||||||
|
if (range instanceof models.Range) {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
if (_.isArray(range)) {
|
||||||
|
if (_.all(function(x) {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = range.length; j < len; j++) {
|
||||||
|
x = range[j];
|
||||||
|
results.push(_.isString(x));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})) {
|
||||||
|
return new models.FactorRange({
|
||||||
|
factors: range
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (range.length === 2) {
|
||||||
|
return new models.Range1d({
|
||||||
|
start: range[0],
|
||||||
|
end: range[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._process_guides = function(dim, axis_type, axis_location, minor_ticks, axis_label) {
|
||||||
|
var axis, axiscls, grid, range;
|
||||||
|
range = dim === 0 ? this.x_range : this.y_range;
|
||||||
|
axiscls = this._get_axis_class(axis_type, range);
|
||||||
|
if (axiscls != null) {
|
||||||
|
if (axiscls === models.LogAxis) {
|
||||||
|
if (dim === 0) {
|
||||||
|
this.x_mapper_type = 'log';
|
||||||
|
} else {
|
||||||
|
this.y_mapper_type = 'log';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
axis = new axiscls();
|
||||||
|
if (axis.ticker instanceof models.ContinuousTicker) {
|
||||||
|
axis.ticker.num_minor_ticks = this._get_num_minor_ticks(axiscls, minor_ticks);
|
||||||
|
}
|
||||||
|
if (axis_label.length !== 0) {
|
||||||
|
axis.axis_label = axis_label;
|
||||||
|
}
|
||||||
|
grid = new models.Grid({
|
||||||
|
dimension: dim,
|
||||||
|
ticker: axis.ticker
|
||||||
|
});
|
||||||
|
this.add_layout(axis, axis_location);
|
||||||
|
return this.add_layout(grid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._get_axis_class = function(axis_type, range) {
|
||||||
|
if (axis_type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (axis_type === "linear") {
|
||||||
|
return models.LinearAxis;
|
||||||
|
}
|
||||||
|
if (axis_type === "log") {
|
||||||
|
return models.LogAxis;
|
||||||
|
}
|
||||||
|
if (axis_type === "datetime") {
|
||||||
|
return models.DatetimeAxis;
|
||||||
|
}
|
||||||
|
if (axis_type === "auto") {
|
||||||
|
if (range instanceof models.FactorRange) {
|
||||||
|
return models.CategoricalAxis;
|
||||||
|
} else {
|
||||||
|
return models.LinearAxis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._get_num_minor_ticks = function(axis_class, num_minor_ticks) {
|
||||||
|
if (_.isNumber(num_minor_ticks)) {
|
||||||
|
if (num_minor_ticks <= 1) {
|
||||||
|
throw new Error("num_minor_ticks must be > 1");
|
||||||
|
}
|
||||||
|
return num_minor_ticks;
|
||||||
|
}
|
||||||
|
if (num_minor_ticks == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (num_minor_ticks === 'auto') {
|
||||||
|
if (axis_class === models.LogAxis) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._process_tools = function(tools) {
|
||||||
|
var objs, tool;
|
||||||
|
if (_.isString(tools)) {
|
||||||
|
tools = tools.split(/\s*,\s*/);
|
||||||
|
}
|
||||||
|
objs = (function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = tools.length; j < len; j++) {
|
||||||
|
tool = tools[j];
|
||||||
|
if (_.isString(tool)) {
|
||||||
|
results.push(_known_tools[tool](this));
|
||||||
|
} else {
|
||||||
|
results.push(tool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
return objs;
|
||||||
|
};
|
||||||
|
|
||||||
|
Figure.prototype._update_legend = function(legend_name, glyph_renderer) {
|
||||||
|
var j, legends, len, name, ref, renderers;
|
||||||
|
legends = _.clone(this._legend.legends);
|
||||||
|
for (j = 0, len = legends.length; j < len; j++) {
|
||||||
|
ref = legends[j], name = ref[0], renderers = ref[1];
|
||||||
|
if (name === legend_name) {
|
||||||
|
renderers.push(glyph_renderer);
|
||||||
|
this._legend.legends = legends;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legends.push([legend_name, [glyph_renderer]]);
|
||||||
|
return this._legend.legends = legends;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Figure;
|
||||||
|
|
||||||
|
})(models.Plot);
|
||||||
|
|
||||||
|
figure = function(attributes, options) {
|
||||||
|
if (attributes == null) {
|
||||||
|
attributes = {};
|
||||||
|
}
|
||||||
|
if (options == null) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
return new Figure(attributes, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
show = function(obj, target) {
|
||||||
|
var _obj, div, doc, j, len, multiple, views;
|
||||||
|
multiple = _.isArray(obj);
|
||||||
|
doc = new Document();
|
||||||
|
if (!multiple) {
|
||||||
|
doc.add_root(obj);
|
||||||
|
} else {
|
||||||
|
for (j = 0, len = obj.length; j < len; j++) {
|
||||||
|
_obj = obj[j];
|
||||||
|
doc.add_root(_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div = $("<div class=" + BOKEH_ROOT + ">");
|
||||||
|
$(target != null ? target : "body").append(div);
|
||||||
|
views = embed.add_document_standalone(doc, div);
|
||||||
|
if (!multiple) {
|
||||||
|
return views[obj.id];
|
||||||
|
} else {
|
||||||
|
return views;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
color = function(r, g, b) {
|
||||||
|
return sprintf("#%02x%02x%02x", r, g, b);
|
||||||
|
};
|
||||||
|
|
||||||
|
gridplot = function(children, options) {
|
||||||
|
var grid, item, j, k, l, layout, len, len1, len2, neighbor, row, row_children, row_tools, rows, sizing_mode, toolbar, toolbar_location, toolbar_sizing_mode, tools;
|
||||||
|
if (options == null) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
toolbar_location = _.isUndefined(options.toolbar_location) ? 'above' : options.toolbar_location;
|
||||||
|
sizing_mode = _.isUndefined(options.sizing_mode) ? 'fixed' : options.sizing_mode;
|
||||||
|
toolbar_sizing_mode = options.sizing_mode === 'fixed' ? 'scale_width' : sizing_mode;
|
||||||
|
tools = [];
|
||||||
|
rows = [];
|
||||||
|
for (j = 0, len = children.length; j < len; j++) {
|
||||||
|
row = children[j];
|
||||||
|
row_tools = [];
|
||||||
|
row_children = [];
|
||||||
|
for (k = 0, len1 = row.length; k < len1; k++) {
|
||||||
|
item = row[k];
|
||||||
|
if (item instanceof models.Plot) {
|
||||||
|
row_tools = row_tools.concat(item.toolbar.tools);
|
||||||
|
item.toolbar_location = null;
|
||||||
|
}
|
||||||
|
if (item === null) {
|
||||||
|
for (l = 0, len2 = row.length; l < len2; l++) {
|
||||||
|
neighbor = row[l];
|
||||||
|
if (neighbor instanceof models.Plot) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item = new models.Spacer({
|
||||||
|
width: neighbor.plot_width,
|
||||||
|
height: neighbor.plot_height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item instanceof models.LayoutDOM) {
|
||||||
|
item.sizing_mode = sizing_mode;
|
||||||
|
row_children.push(item);
|
||||||
|
} else {
|
||||||
|
throw new Error("only LayoutDOM items can be inserted into Grid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tools = tools.concat(row_tools);
|
||||||
|
row = new models.Row({
|
||||||
|
children: row_children,
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
grid = new models.Column({
|
||||||
|
children: rows,
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
layout = (function() {
|
||||||
|
if (toolbar_location) {
|
||||||
|
toolbar = new models.ToolbarBox({
|
||||||
|
tools: tools,
|
||||||
|
sizing_mode: toolbar_sizing_mode,
|
||||||
|
toolbar_location: toolbar_location
|
||||||
|
});
|
||||||
|
switch (toolbar_location) {
|
||||||
|
case 'above':
|
||||||
|
return new models.Column({
|
||||||
|
children: [toolbar, grid],
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
case 'below':
|
||||||
|
return new models.Column({
|
||||||
|
children: [grid, toolbar],
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
case 'left':
|
||||||
|
return new models.Row({
|
||||||
|
children: [toolbar, grid],
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
case 'right':
|
||||||
|
return new models.Row({
|
||||||
|
children: [grid, toolbar],
|
||||||
|
sizing_mode: sizing_mode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Figure: Figure,
|
||||||
|
figure: figure,
|
||||||
|
show: show,
|
||||||
|
color: color,
|
||||||
|
gridplot: gridplot
|
||||||
|
};
|
|
@ -0,0 +1,97 @@
|
||||||
|
var Models, _, _get_mod_cache, _mod_cache, index, locations, logger, make_cache, overrides,
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
logger = require("./core/logging").logger;
|
||||||
|
|
||||||
|
require("./core/util/underscore").patch();
|
||||||
|
|
||||||
|
locations = require("./common/models");
|
||||||
|
|
||||||
|
overrides = {};
|
||||||
|
|
||||||
|
make_cache = function(locations) {
|
||||||
|
var mod, modname, name, ref, result, spec, subname, subspec, suffix;
|
||||||
|
result = {};
|
||||||
|
for (name in locations) {
|
||||||
|
spec = locations[name];
|
||||||
|
if (_.isArray(spec)) {
|
||||||
|
subspec = spec[0];
|
||||||
|
suffix = (ref = spec[1]) != null ? ref : "";
|
||||||
|
for (subname in subspec) {
|
||||||
|
mod = subspec[subname];
|
||||||
|
modname = subname + suffix;
|
||||||
|
result[modname] = mod;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result[name] = spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
_mod_cache = null;
|
||||||
|
|
||||||
|
_get_mod_cache = function() {
|
||||||
|
if (_mod_cache == null) {
|
||||||
|
_mod_cache = make_cache(locations);
|
||||||
|
}
|
||||||
|
return _mod_cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
Models = function(typename) {
|
||||||
|
var mod, mod_cache;
|
||||||
|
mod_cache = _get_mod_cache();
|
||||||
|
if (overrides[typename]) {
|
||||||
|
return overrides[typename];
|
||||||
|
}
|
||||||
|
mod = mod_cache[typename];
|
||||||
|
if (mod == null) {
|
||||||
|
throw new Error("Module `" + typename + "' does not exists. The problem may be two fold. Either a model was requested that's available in an extra bundle, e.g. a widget, or a custom model was requested, but it wasn't registered before first usage.");
|
||||||
|
}
|
||||||
|
return mod.Model;
|
||||||
|
};
|
||||||
|
|
||||||
|
Models.register = function(name, model) {
|
||||||
|
return overrides[name] = model;
|
||||||
|
};
|
||||||
|
|
||||||
|
Models.unregister = function(name) {
|
||||||
|
return delete overrides[name];
|
||||||
|
};
|
||||||
|
|
||||||
|
Models.register_locations = function(locations, force, errorFn) {
|
||||||
|
var cache, mod_cache, module, name, results;
|
||||||
|
if (force == null) {
|
||||||
|
force = false;
|
||||||
|
}
|
||||||
|
if (errorFn == null) {
|
||||||
|
errorFn = null;
|
||||||
|
}
|
||||||
|
mod_cache = _get_mod_cache();
|
||||||
|
cache = make_cache(locations);
|
||||||
|
results = [];
|
||||||
|
for (name in cache) {
|
||||||
|
if (!hasProp.call(cache, name)) continue;
|
||||||
|
module = cache[name];
|
||||||
|
if (force || !mod_cache.hasOwnProperty(name)) {
|
||||||
|
results.push(mod_cache[name] = module);
|
||||||
|
} else {
|
||||||
|
results.push(typeof errorFn === "function" ? errorFn(name) : void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
Models.registered_names = function() {
|
||||||
|
return Object.keys(_get_mod_cache());
|
||||||
|
};
|
||||||
|
|
||||||
|
index = {};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
overrides: overrides,
|
||||||
|
index: index,
|
||||||
|
Models: Models
|
||||||
|
};
|
|
@ -0,0 +1,605 @@
|
||||||
|
var ClientConnection, ClientSession, DEFAULT_SERVER_WEBSOCKET_URL, DEFAULT_SESSION_ID, Document, HasProps, Message, ModelChangedEvent, Promise, RootAddedEvent, RootRemovedEvent, _, logger, message_handlers, pull_session, ref;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Promise = require("es6-promise").Promise;
|
||||||
|
|
||||||
|
HasProps = require("./core/has_props");
|
||||||
|
|
||||||
|
logger = require("./core/logging").logger;
|
||||||
|
|
||||||
|
ref = require("./document"), Document = ref.Document, ModelChangedEvent = ref.ModelChangedEvent, RootAddedEvent = ref.RootAddedEvent, RootRemovedEvent = ref.RootRemovedEvent;
|
||||||
|
|
||||||
|
DEFAULT_SERVER_WEBSOCKET_URL = "ws://localhost:5006/ws";
|
||||||
|
|
||||||
|
DEFAULT_SESSION_ID = "default";
|
||||||
|
|
||||||
|
Message = (function() {
|
||||||
|
function Message(header1, metadata1, content1) {
|
||||||
|
this.header = header1;
|
||||||
|
this.metadata = metadata1;
|
||||||
|
this.content = content1;
|
||||||
|
this.buffers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Message.assemble = function(header_json, metadata_json, content_json) {
|
||||||
|
var content, e, error1, header, metadata;
|
||||||
|
try {
|
||||||
|
header = JSON.parse(header_json);
|
||||||
|
metadata = JSON.parse(metadata_json);
|
||||||
|
content = JSON.parse(content_json);
|
||||||
|
return new Message(header, metadata, content);
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
logger.error("Failure parsing json " + e + " " + header_json + " " + metadata_json + " " + content_json, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.create_header = function(msgtype, options) {
|
||||||
|
var header;
|
||||||
|
header = {
|
||||||
|
'msgid': _.uniqueId(),
|
||||||
|
'msgtype': msgtype
|
||||||
|
};
|
||||||
|
return _.extend(header, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.create = function(msgtype, header_options, content) {
|
||||||
|
var header;
|
||||||
|
if (content == null) {
|
||||||
|
content = {};
|
||||||
|
}
|
||||||
|
header = Message.create_header(msgtype, header_options);
|
||||||
|
return new Message(header, {}, content);
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.send = function(socket) {
|
||||||
|
var content_json, e, error1, header_json, metadata_json;
|
||||||
|
try {
|
||||||
|
header_json = JSON.stringify(this.header);
|
||||||
|
metadata_json = JSON.stringify(this.metadata);
|
||||||
|
content_json = JSON.stringify(this.content);
|
||||||
|
socket.send(header_json);
|
||||||
|
socket.send(metadata_json);
|
||||||
|
return socket.send(content_json);
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
logger.error("Error sending ", this, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.complete = function() {
|
||||||
|
if ((this.header != null) && (this.metadata != null) && (this.content != null)) {
|
||||||
|
if ('num_buffers' in this.header) {
|
||||||
|
return this.buffers.length === this.header['num_buffers'];
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.add_buffer = function(buffer) {
|
||||||
|
return this.buffers.push(buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype._header_field = function(field) {
|
||||||
|
if (field in this.header) {
|
||||||
|
return this.header[field];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.msgid = function() {
|
||||||
|
return this._header_field('msgid');
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.msgtype = function() {
|
||||||
|
return this._header_field('msgtype');
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.sessid = function() {
|
||||||
|
return this._header_field('sessid');
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.reqid = function() {
|
||||||
|
return this._header_field('reqid');
|
||||||
|
};
|
||||||
|
|
||||||
|
Message.prototype.problem = function() {
|
||||||
|
if (!('msgid' in this.header)) {
|
||||||
|
return "No msgid in header";
|
||||||
|
} else if (!('msgtype' in this.header)) {
|
||||||
|
return "No msgtype in header";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Message;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
message_handlers = {
|
||||||
|
'PATCH-DOC': function(connection, message) {
|
||||||
|
return connection._for_session(function(session) {
|
||||||
|
return session._handle_patch(message);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'OK': function(connection, message) {
|
||||||
|
return logger.debug("Unhandled OK reply to " + (message.reqid()));
|
||||||
|
},
|
||||||
|
'ERROR': function(connection, message) {
|
||||||
|
return logger.error("Unhandled ERROR reply to " + (message.reqid()) + ": " + message.content['text']);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection = (function() {
|
||||||
|
ClientConnection._connection_count = 0;
|
||||||
|
|
||||||
|
function ClientConnection(url1, id, _on_have_session_hook, _on_closed_permanently_hook) {
|
||||||
|
this.url = url1;
|
||||||
|
this.id = id;
|
||||||
|
this._on_have_session_hook = _on_have_session_hook;
|
||||||
|
this._on_closed_permanently_hook = _on_closed_permanently_hook;
|
||||||
|
this._number = ClientConnection._connection_count;
|
||||||
|
ClientConnection._connection_count = this._number + 1;
|
||||||
|
if (this.url == null) {
|
||||||
|
this.url = DEFAULT_SERVER_WEBSOCKET_URL;
|
||||||
|
}
|
||||||
|
if (this.id == null) {
|
||||||
|
this.id = DEFAULT_SESSION_ID;
|
||||||
|
}
|
||||||
|
logger.debug("Creating websocket " + this._number + " to '" + this.url + "' session '" + this.id + "'");
|
||||||
|
this.socket = null;
|
||||||
|
this.closed_permanently = false;
|
||||||
|
this._fragments = [];
|
||||||
|
this._partial = null;
|
||||||
|
this._current_handler = null;
|
||||||
|
this._pending_ack = null;
|
||||||
|
this._pending_replies = {};
|
||||||
|
this.session = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientConnection.prototype._for_session = function(f) {
|
||||||
|
if (this.session !== null) {
|
||||||
|
return f(this.session);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype.connect = function() {
|
||||||
|
var error, error1, versioned_url;
|
||||||
|
if (this.closed_permanently) {
|
||||||
|
return Promise.reject(new Error("Cannot connect() a closed ClientConnection"));
|
||||||
|
}
|
||||||
|
if (this.socket != null) {
|
||||||
|
return Promise.reject(new Error("Already connected"));
|
||||||
|
}
|
||||||
|
this._fragments = [];
|
||||||
|
this._partial = null;
|
||||||
|
this._pending_replies = {};
|
||||||
|
this._current_handler = null;
|
||||||
|
try {
|
||||||
|
versioned_url = this.url + "?bokeh-protocol-version=1.0&bokeh-session-id=" + this.id;
|
||||||
|
if (window.MozWebSocket != null) {
|
||||||
|
this.socket = new MozWebSocket(versioned_url);
|
||||||
|
} else {
|
||||||
|
this.socket = new WebSocket(versioned_url);
|
||||||
|
}
|
||||||
|
return new Promise((function(_this) {
|
||||||
|
return function(resolve, reject) {
|
||||||
|
_this.socket.binarytype = "arraybuffer";
|
||||||
|
_this.socket.onopen = function() {
|
||||||
|
return _this._on_open(resolve, reject);
|
||||||
|
};
|
||||||
|
_this.socket.onmessage = function(event) {
|
||||||
|
return _this._on_message(event);
|
||||||
|
};
|
||||||
|
_this.socket.onclose = function(event) {
|
||||||
|
return _this._on_close(event);
|
||||||
|
};
|
||||||
|
return _this.socket.onerror = function() {
|
||||||
|
return _this._on_error(reject);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
} catch (error1) {
|
||||||
|
error = error1;
|
||||||
|
logger.error("websocket creation failed to url: " + this.url);
|
||||||
|
logger.error(" - " + error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype.close = function() {
|
||||||
|
if (!this.closed_permanently) {
|
||||||
|
logger.debug("Permanently closing websocket connection " + this._number);
|
||||||
|
this.closed_permanently = true;
|
||||||
|
if (this.socket != null) {
|
||||||
|
this.socket.close(1000, "close method called on ClientConnection " + this._number);
|
||||||
|
}
|
||||||
|
this._for_session(function(session) {
|
||||||
|
return session._connection_closed();
|
||||||
|
});
|
||||||
|
if (this._on_closed_permanently_hook != null) {
|
||||||
|
this._on_closed_permanently_hook();
|
||||||
|
return this._on_closed_permanently_hook = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._schedule_reconnect = function(milliseconds) {
|
||||||
|
var retry;
|
||||||
|
retry = (function(_this) {
|
||||||
|
return function() {
|
||||||
|
if (true || _this.closed_permanently) {
|
||||||
|
if (!_this.closed_permanently) {
|
||||||
|
logger.info("Websocket connection " + _this._number + " disconnected, will not attempt to reconnect");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug("Attempting to reconnect websocket " + _this._number);
|
||||||
|
return _this.connect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
return setTimeout(retry, milliseconds);
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype.send = function(message) {
|
||||||
|
var e, error1;
|
||||||
|
try {
|
||||||
|
if (this.socket === null) {
|
||||||
|
throw new Error("not connected so cannot send " + message);
|
||||||
|
}
|
||||||
|
return message.send(this.socket);
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
return logger.error("Error sending message ", e, message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype.send_with_reply = function(message) {
|
||||||
|
var promise;
|
||||||
|
promise = new Promise((function(_this) {
|
||||||
|
return function(resolve, reject) {
|
||||||
|
_this._pending_replies[message.msgid()] = [resolve, reject];
|
||||||
|
return _this.send(message);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
return promise.then(function(message) {
|
||||||
|
if (message.msgtype() === 'ERROR') {
|
||||||
|
throw new Error("Error reply " + message.content['text']);
|
||||||
|
} else {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}, function(error) {
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._pull_doc_json = function() {
|
||||||
|
var message, promise;
|
||||||
|
message = Message.create('PULL-DOC-REQ', {});
|
||||||
|
promise = this.send_with_reply(message);
|
||||||
|
return promise.then(function(reply) {
|
||||||
|
if (!('doc' in reply.content)) {
|
||||||
|
throw new Error("No 'doc' field in PULL-DOC-REPLY");
|
||||||
|
}
|
||||||
|
return reply.content['doc'];
|
||||||
|
}, function(error) {
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._repull_session_doc = function() {
|
||||||
|
if (this.session === null) {
|
||||||
|
logger.debug("Pulling session for first time");
|
||||||
|
} else {
|
||||||
|
logger.debug("Repulling session");
|
||||||
|
}
|
||||||
|
return this._pull_doc_json().then((function(_this) {
|
||||||
|
return function(doc_json) {
|
||||||
|
var document, patch, patch_message;
|
||||||
|
if (_this.session === null) {
|
||||||
|
if (_this.closed_permanently) {
|
||||||
|
return logger.debug("Got new document after connection was already closed");
|
||||||
|
} else {
|
||||||
|
document = Document.from_json(doc_json);
|
||||||
|
patch = Document._compute_patch_since_json(doc_json, document);
|
||||||
|
if (patch.events.length > 0) {
|
||||||
|
logger.debug("Sending " + patch.events.length + " changes from model construction back to server");
|
||||||
|
patch_message = Message.create('PATCH-DOC', {}, patch);
|
||||||
|
_this.send(patch_message);
|
||||||
|
}
|
||||||
|
_this.session = new ClientSession(_this, document, _this.id);
|
||||||
|
logger.debug("Created a new session from new pulled doc");
|
||||||
|
if (_this._on_have_session_hook != null) {
|
||||||
|
_this._on_have_session_hook(_this.session);
|
||||||
|
return _this._on_have_session_hook = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_this.session.document.replace_with_json(doc_json);
|
||||||
|
return logger.debug("Updated existing session with new pulled doc");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this), function(error) {
|
||||||
|
throw error;
|
||||||
|
})["catch"](function(error) {
|
||||||
|
if (console.trace != null) {
|
||||||
|
console.trace(error);
|
||||||
|
}
|
||||||
|
return logger.error("Failed to repull session " + error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._on_open = function(resolve, reject) {
|
||||||
|
logger.info("Websocket connection " + this._number + " is now open");
|
||||||
|
this._pending_ack = [resolve, reject];
|
||||||
|
return this._current_handler = (function(_this) {
|
||||||
|
return function(message) {
|
||||||
|
return _this._awaiting_ack_handler(message);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._on_message = function(event) {
|
||||||
|
var e, error1;
|
||||||
|
try {
|
||||||
|
return this._on_message_unchecked(event);
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
return logger.error("Error handling message: " + e + ", " + event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._on_message_unchecked = function(event) {
|
||||||
|
var msg, problem;
|
||||||
|
if (this._current_handler == null) {
|
||||||
|
logger.error("got a message but haven't set _current_handler");
|
||||||
|
}
|
||||||
|
if (event.data instanceof ArrayBuffer) {
|
||||||
|
if ((this._partial != null) && !this._partial.complete()) {
|
||||||
|
this._partial.add_buffer(event.data);
|
||||||
|
} else {
|
||||||
|
this._close_bad_protocol("Got binary from websocket but we were expecting text");
|
||||||
|
}
|
||||||
|
} else if (this._partial != null) {
|
||||||
|
this._close_bad_protocol("Got text from websocket but we were expecting binary");
|
||||||
|
} else {
|
||||||
|
this._fragments.push(event.data);
|
||||||
|
if (this._fragments.length === 3) {
|
||||||
|
this._partial = Message.assemble(this._fragments[0], this._fragments[1], this._fragments[2]);
|
||||||
|
this._fragments = [];
|
||||||
|
problem = this._partial.problem();
|
||||||
|
if (problem !== null) {
|
||||||
|
this._close_bad_protocol(problem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((this._partial != null) && this._partial.complete()) {
|
||||||
|
msg = this._partial;
|
||||||
|
this._partial = null;
|
||||||
|
return this._current_handler(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._on_close = function(event) {
|
||||||
|
var pop_pending, promise_funcs;
|
||||||
|
logger.info("Lost websocket " + this._number + " connection, " + event.code + " (" + event.reason + ")");
|
||||||
|
this.socket = null;
|
||||||
|
if (this._pending_ack != null) {
|
||||||
|
this._pending_ack[1](new Error("Lost websocket connection, " + event.code + " (" + event.reason + ")"));
|
||||||
|
this._pending_ack = null;
|
||||||
|
}
|
||||||
|
pop_pending = function() {
|
||||||
|
var promise_funcs, ref1, reqid;
|
||||||
|
ref1 = this._pending_replies;
|
||||||
|
for (reqid in ref1) {
|
||||||
|
promise_funcs = ref1[reqid];
|
||||||
|
delete this._pending_replies[reqid];
|
||||||
|
return promise_funcs;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
promise_funcs = pop_pending();
|
||||||
|
while (promise_funcs !== null) {
|
||||||
|
promise_funcs[1]("Disconnected");
|
||||||
|
promise_funcs = pop_pending();
|
||||||
|
}
|
||||||
|
if (!this.closed_permanently) {
|
||||||
|
return this._schedule_reconnect(2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._on_error = function(reject) {
|
||||||
|
logger.debug("Websocket error on socket " + this._number);
|
||||||
|
return reject(new Error("Could not open websocket"));
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._close_bad_protocol = function(detail) {
|
||||||
|
logger.error("Closing connection: " + detail);
|
||||||
|
if (this.socket != null) {
|
||||||
|
return this.socket.close(1002, detail);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._awaiting_ack_handler = function(message) {
|
||||||
|
if (message.msgtype() === "ACK") {
|
||||||
|
this._current_handler = (function(_this) {
|
||||||
|
return function(message) {
|
||||||
|
return _this._steady_state_handler(message);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
this._repull_session_doc();
|
||||||
|
if (this._pending_ack != null) {
|
||||||
|
this._pending_ack[0](this);
|
||||||
|
return this._pending_ack = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this._close_bad_protocol("First message was not an ACK");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientConnection.prototype._steady_state_handler = function(message) {
|
||||||
|
var promise_funcs;
|
||||||
|
if (message.reqid() in this._pending_replies) {
|
||||||
|
promise_funcs = this._pending_replies[message.reqid()];
|
||||||
|
delete this._pending_replies[message.reqid()];
|
||||||
|
return promise_funcs[0](message);
|
||||||
|
} else if (message.msgtype() in message_handlers) {
|
||||||
|
return message_handlers[message.msgtype()](this, message);
|
||||||
|
} else {
|
||||||
|
return logger.debug("Doing nothing with message " + (message.msgtype()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ClientConnection;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
ClientSession = (function() {
|
||||||
|
function ClientSession(_connection, document1, id) {
|
||||||
|
this._connection = _connection;
|
||||||
|
this.document = document1;
|
||||||
|
this.id = id;
|
||||||
|
this._current_patch = null;
|
||||||
|
this.document_listener = (function(_this) {
|
||||||
|
return function(event) {
|
||||||
|
return _this._document_changed(event);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
this.document.on_change(this.document_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientSession.prototype.close = function() {
|
||||||
|
return this._connection.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype._connection_closed = function() {
|
||||||
|
return this.document.remove_on_change(this.document_listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype.request_server_info = function() {
|
||||||
|
var message, promise;
|
||||||
|
message = Message.create('SERVER-INFO-REQ', {});
|
||||||
|
promise = this._connection.send_with_reply(message);
|
||||||
|
return promise.then(function(reply) {
|
||||||
|
return reply.content;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype.force_roundtrip = function() {
|
||||||
|
return this.request_server_info().then(function(ignored) {
|
||||||
|
return void 0;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype._should_suppress_on_change = function(patch, event) {
|
||||||
|
var event_json, i, j, k, l, len, len1, len2, len3, patch_new, ref1, ref2, ref3, ref4;
|
||||||
|
if (event instanceof ModelChangedEvent) {
|
||||||
|
ref1 = patch.content['events'];
|
||||||
|
for (i = 0, len = ref1.length; i < len; i++) {
|
||||||
|
event_json = ref1[i];
|
||||||
|
if (event_json['kind'] === 'ModelChanged' && event_json['model']['id'] === event.model.id && event_json['attr'] === event.attr) {
|
||||||
|
patch_new = event_json['new'];
|
||||||
|
if (event.new_ instanceof HasProps) {
|
||||||
|
if (typeof patch_new === 'object' && 'id' in patch_new && patch_new['id'] === event.new_.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (_.isEqual(patch_new, event.new_)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event instanceof RootAddedEvent) {
|
||||||
|
ref2 = patch.content['events'];
|
||||||
|
for (j = 0, len1 = ref2.length; j < len1; j++) {
|
||||||
|
event_json = ref2[j];
|
||||||
|
if (event_json['kind'] === 'RootAdded' && event_json['model']['id'] === event.model.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event instanceof RootRemovedEvent) {
|
||||||
|
ref3 = patch.content['events'];
|
||||||
|
for (k = 0, len2 = ref3.length; k < len2; k++) {
|
||||||
|
event_json = ref3[k];
|
||||||
|
if (event_json['kind'] === 'RootRemoved' && event_json['model']['id'] === event.model.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event instanceof TitleChangedEvent) {
|
||||||
|
ref4 = patch.content['events'];
|
||||||
|
for (l = 0, len3 = ref4.length; l < len3; l++) {
|
||||||
|
event_json = ref4[l];
|
||||||
|
if (event_json['kind'] === 'TitleChanged' && event_json['title'] === event.title) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype._document_changed = function(event) {
|
||||||
|
var patch;
|
||||||
|
if ((this._current_patch != null) && this._should_suppress_on_change(this._current_patch, event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event instanceof ModelChangedEvent && !(event.attr in event.model.serializable_attributes())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
patch = Message.create('PATCH-DOC', {}, this.document.create_json_patch([event]));
|
||||||
|
return this._connection.send(patch);
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientSession.prototype._handle_patch = function(message) {
|
||||||
|
this._current_patch = message;
|
||||||
|
try {
|
||||||
|
return this.document.apply_json_patch(message.content);
|
||||||
|
} finally {
|
||||||
|
this._current_patch = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ClientSession;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
pull_session = function(url, session_id) {
|
||||||
|
var connection, promise, rejecter;
|
||||||
|
rejecter = null;
|
||||||
|
connection = null;
|
||||||
|
promise = new Promise(function(resolve, reject) {
|
||||||
|
connection = new ClientConnection(url, session_id, function(session) {
|
||||||
|
var e, error1;
|
||||||
|
try {
|
||||||
|
return resolve(session);
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
logger.error("Promise handler threw an error, closing session " + error);
|
||||||
|
session.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}, function() {
|
||||||
|
return reject(new Error("Connection was closed before we successfully pulled a session"));
|
||||||
|
});
|
||||||
|
return connection.connect().then(function(whatever) {}, function(error) {
|
||||||
|
logger.error("Failed to connect to Bokeh server " + error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
promise.close = function() {
|
||||||
|
return connection.close();
|
||||||
|
};
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
pull_session: pull_session,
|
||||||
|
DEFAULT_SERVER_WEBSOCKET_URL: DEFAULT_SERVER_WEBSOCKET_URL,
|
||||||
|
DEFAULT_SESSION_ID: DEFAULT_SESSION_ID
|
||||||
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
var _, build_views, jQueryUIPrefixer;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
build_views = function(view_storage, view_models, options, view_types) {
|
||||||
|
var created_views, i, i_model, j, key, len, len1, model, newmodels, to_remove, view_specific_option;
|
||||||
|
if (view_types == null) {
|
||||||
|
view_types = [];
|
||||||
|
}
|
||||||
|
created_views = [];
|
||||||
|
newmodels = _.filter(view_models, function(x) {
|
||||||
|
return !_.has(view_storage, x.id);
|
||||||
|
});
|
||||||
|
for (i_model = i = 0, len = newmodels.length; i < len; i_model = ++i) {
|
||||||
|
model = newmodels[i_model];
|
||||||
|
view_specific_option = _.extend({}, options, {
|
||||||
|
'model': model
|
||||||
|
});
|
||||||
|
if (i_model < view_types.length) {
|
||||||
|
view_storage[model.id] = new view_types[i_model](view_specific_option);
|
||||||
|
} else {
|
||||||
|
view_storage[model.id] = new model.default_view(view_specific_option);
|
||||||
|
}
|
||||||
|
view_storage[model.id].$el.find("*[class*='ui-']").each(function(idx, el) {
|
||||||
|
return el.className = jQueryUIPrefixer(el);
|
||||||
|
});
|
||||||
|
created_views.push(view_storage[model.id]);
|
||||||
|
}
|
||||||
|
to_remove = _.difference(_.keys(view_storage), _.pluck(view_models, 'id'));
|
||||||
|
for (j = 0, len1 = to_remove.length; j < len1; j++) {
|
||||||
|
key = to_remove[j];
|
||||||
|
view_storage[key].remove();
|
||||||
|
delete view_storage[key];
|
||||||
|
}
|
||||||
|
return created_views;
|
||||||
|
};
|
||||||
|
|
||||||
|
jQueryUIPrefixer = function(el) {
|
||||||
|
var classList, prefixedClassList;
|
||||||
|
if (el.className == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
classList = el.className.split(" ");
|
||||||
|
prefixedClassList = _.map(classList, function(a) {
|
||||||
|
a = a.trim();
|
||||||
|
if (a.indexOf("ui-") === 0) {
|
||||||
|
return "bk-" + a;
|
||||||
|
} else {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return prefixedClassList.join(" ");
|
||||||
|
};
|
||||||
|
|
||||||
|
build_views.jQueryUIPrefixer = jQueryUIPrefixer;
|
||||||
|
|
||||||
|
module.exports = build_views = build_views;
|
|
@ -0,0 +1,156 @@
|
||||||
|
var HitTestResult, check_2_segments_intersect, create_hit_test_result, dist_2_pts, dist_to_segment, dist_to_segment_squared, nullreturner, point_in_poly, sqr, validate_bbox_coords;
|
||||||
|
|
||||||
|
point_in_poly = function(x, y, px, py) {
|
||||||
|
var i, inside, j, ref, x1, x2, y1, y2;
|
||||||
|
inside = false;
|
||||||
|
x1 = px[px.length - 1];
|
||||||
|
y1 = py[py.length - 1];
|
||||||
|
for (i = j = 0, ref = px.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
x2 = px[i];
|
||||||
|
y2 = py[i];
|
||||||
|
if ((y1 < y) !== (y2 < y)) {
|
||||||
|
if (x1 + (y - y1) / (y2 - y1) * (x2 - x1) < x) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x1 = x2;
|
||||||
|
y1 = y2;
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
};
|
||||||
|
|
||||||
|
nullreturner = function() {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
HitTestResult = (function() {
|
||||||
|
function HitTestResult() {
|
||||||
|
this['0d'] = {
|
||||||
|
glyph: null,
|
||||||
|
get_view: nullreturner,
|
||||||
|
indices: []
|
||||||
|
};
|
||||||
|
this['1d'] = {
|
||||||
|
indices: []
|
||||||
|
};
|
||||||
|
this['2d'] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(HitTestResult.prototype, '_0d', {
|
||||||
|
get: function() {
|
||||||
|
return this['0d'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(HitTestResult.prototype, '_1d', {
|
||||||
|
get: function() {
|
||||||
|
return this['1d'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(HitTestResult.prototype, '_2d', {
|
||||||
|
get: function() {
|
||||||
|
return this['2d'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HitTestResult.prototype.is_empty = function() {
|
||||||
|
return this._0d.indices.length === 0 && this._1d.indices.length === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return HitTestResult;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
create_hit_test_result = function() {
|
||||||
|
return new HitTestResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
validate_bbox_coords = function(arg, arg1) {
|
||||||
|
var ref, ref1, x0, x1, y0, y1;
|
||||||
|
x0 = arg[0], x1 = arg[1];
|
||||||
|
y0 = arg1[0], y1 = arg1[1];
|
||||||
|
if (x0 > x1) {
|
||||||
|
ref = [x1, x0], x0 = ref[0], x1 = ref[1];
|
||||||
|
}
|
||||||
|
if (y0 > y1) {
|
||||||
|
ref1 = [y1, y0], y0 = ref1[0], y1 = ref1[1];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
minX: x0,
|
||||||
|
minY: y0,
|
||||||
|
maxX: x1,
|
||||||
|
maxY: y1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sqr = function(x) {
|
||||||
|
return x * x;
|
||||||
|
};
|
||||||
|
|
||||||
|
dist_2_pts = function(vx, vy, wx, wy) {
|
||||||
|
return sqr(vx - wx) + sqr(vy - wy);
|
||||||
|
};
|
||||||
|
|
||||||
|
dist_to_segment_squared = function(p, v, w) {
|
||||||
|
var l2, t;
|
||||||
|
l2 = dist_2_pts(v.x, v.y, w.x, w.y);
|
||||||
|
if (l2 === 0) {
|
||||||
|
return dist_2_pts(p.x, p.y, v.x, v.y);
|
||||||
|
}
|
||||||
|
t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
|
||||||
|
if (t < 0) {
|
||||||
|
return dist_2_pts(p.x, p.y, v.x, v.y);
|
||||||
|
}
|
||||||
|
if (t > 1) {
|
||||||
|
return dist_2_pts(p.x, p.y, w.x, w.y);
|
||||||
|
}
|
||||||
|
return dist_2_pts(p.x, p.y, v.x + t * (w.x - v.x), v.y + t * (w.y - v.y));
|
||||||
|
};
|
||||||
|
|
||||||
|
dist_to_segment = function(p, v, w) {
|
||||||
|
return Math.sqrt(dist_to_segment_squared(p, v, w));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_2_segments_intersect = function(l0_x0, l0_y0, l0_x1, l0_y1, l1_x0, l1_y0, l1_x1, l1_y1) {
|
||||||
|
|
||||||
|
/* Check if 2 segments (l0 and l1) intersect. Returns a structure with
|
||||||
|
the following attributes:
|
||||||
|
* hit (boolean): whether the 2 segments intersect
|
||||||
|
* x (float): x coordinate of the intersection point
|
||||||
|
* y (float): y coordinate of the intersection point
|
||||||
|
*/
|
||||||
|
var a, b, den, num1, num2, x, y;
|
||||||
|
den = ((l1_y1 - l1_y0) * (l0_x1 - l0_x0)) - ((l1_x1 - l1_x0) * (l0_y1 - l0_y0));
|
||||||
|
if (den === 0) {
|
||||||
|
return {
|
||||||
|
hit: false,
|
||||||
|
x: null,
|
||||||
|
y: null
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
a = l0_y0 - l1_y0;
|
||||||
|
b = l0_x0 - l1_x0;
|
||||||
|
num1 = ((l1_x1 - l1_x0) * a) - ((l1_y1 - l1_y0) * b);
|
||||||
|
num2 = ((l0_x1 - l0_x0) * a) - ((l0_y1 - l0_y0) * b);
|
||||||
|
a = num1 / den;
|
||||||
|
b = num2 / den;
|
||||||
|
x = l0_x0 + (a * (l0_x1 - l0_x0));
|
||||||
|
y = l0_y0 + (a * (l0_y1 - l0_y0));
|
||||||
|
return {
|
||||||
|
hit: (a > 0 && a < 1) && (b > 0 && b < 1),
|
||||||
|
x: x,
|
||||||
|
y: y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
point_in_poly: point_in_poly,
|
||||||
|
HitTestResult: HitTestResult,
|
||||||
|
create_hit_test_result: create_hit_test_result,
|
||||||
|
dist_2_pts: dist_2_pts,
|
||||||
|
dist_to_segment: dist_to_segment,
|
||||||
|
check_2_segments_intersect: check_2_segments_intersect,
|
||||||
|
validate_bbox_coords: validate_bbox_coords
|
||||||
|
};
|
|
@ -0,0 +1,136 @@
|
||||||
|
module.exports = {
|
||||||
|
SelectionManager: require('./selection_manager'),
|
||||||
|
Selector: require('./selector'),
|
||||||
|
ToolEvents: require('./tool_events'),
|
||||||
|
Arrow: require('../models/annotations/arrow'),
|
||||||
|
BoxAnnotation: require('../models/annotations/box_annotation'),
|
||||||
|
ColorBar: require('../models/annotations/color_bar'),
|
||||||
|
Label: require('../models/annotations/label'),
|
||||||
|
LabelSet: require('../models/annotations/label_set'),
|
||||||
|
Legend: require('../models/annotations/legend'),
|
||||||
|
PolyAnnotation: require('../models/annotations/poly_annotation'),
|
||||||
|
Span: require('../models/annotations/span'),
|
||||||
|
Title: require('../models/annotations/title'),
|
||||||
|
Tooltip: require('../models/annotations/tooltip'),
|
||||||
|
OpenHead: require('../models/annotations/arrow_head').OpenHead,
|
||||||
|
NormalHead: require('../models/annotations/arrow_head').NormalHead,
|
||||||
|
VeeHead: require('../models/annotations/arrow_head').VeeHead,
|
||||||
|
CategoricalAxis: require('../models/axes/categorical_axis'),
|
||||||
|
DatetimeAxis: require('../models/axes/datetime_axis'),
|
||||||
|
LinearAxis: require('../models/axes/linear_axis'),
|
||||||
|
LogAxis: require('../models/axes/log_axis'),
|
||||||
|
CustomJS: require('../models/callbacks/customjs'),
|
||||||
|
OpenURL: require('../models/callbacks/open_url'),
|
||||||
|
Canvas: require('../models/canvas/canvas'),
|
||||||
|
CartesianFrame: require('../models/canvas/cartesian_frame'),
|
||||||
|
BasicTickFormatter: require('../models/formatters/basic_tick_formatter'),
|
||||||
|
CategoricalTickFormatter: require('../models/formatters/categorical_tick_formatter'),
|
||||||
|
DatetimeTickFormatter: require('../models/formatters/datetime_tick_formatter'),
|
||||||
|
LogTickFormatter: require('../models/formatters/log_tick_formatter'),
|
||||||
|
FuncTickFormatter: require('../models/formatters/func_tick_formatter'),
|
||||||
|
NumeralTickFormatter: require('../models/formatters/numeral_tick_formatter'),
|
||||||
|
PrintfTickFormatter: require('../models/formatters/printf_tick_formatter'),
|
||||||
|
AnnularWedge: require('../models/glyphs/annular_wedge'),
|
||||||
|
Annulus: require('../models/glyphs/annulus'),
|
||||||
|
Arc: require('../models/glyphs/arc'),
|
||||||
|
Bezier: require('../models/glyphs/bezier'),
|
||||||
|
Circle: require('../models/glyphs/circle'),
|
||||||
|
Ellipse: require('../models/glyphs/ellipse'),
|
||||||
|
Gear: require('../models/glyphs/gear'),
|
||||||
|
HBar: require('../models/glyphs/hbar'),
|
||||||
|
Image: require('../models/glyphs/image'),
|
||||||
|
ImageRGBA: require('../models/glyphs/image_rgba'),
|
||||||
|
ImageURL: require('../models/glyphs/image_url'),
|
||||||
|
Line: require('../models/glyphs/line'),
|
||||||
|
MultiLine: require('../models/glyphs/multi_line'),
|
||||||
|
Oval: require('../models/glyphs/oval'),
|
||||||
|
Patch: require('../models/glyphs/patch'),
|
||||||
|
Patches: require('../models/glyphs/patches'),
|
||||||
|
Quad: require('../models/glyphs/quad'),
|
||||||
|
Quadratic: require('../models/glyphs/quadratic'),
|
||||||
|
Ray: require('../models/glyphs/ray'),
|
||||||
|
Rect: require('../models/glyphs/rect'),
|
||||||
|
Segment: require('../models/glyphs/segment'),
|
||||||
|
Text: require('../models/glyphs/text'),
|
||||||
|
VBar: require('../models/glyphs/vbar'),
|
||||||
|
Wedge: require('../models/glyphs/wedge'),
|
||||||
|
Grid: require('../models/grids/grid'),
|
||||||
|
Column: require('../models/layouts/column'),
|
||||||
|
Row: require('../models/layouts/row'),
|
||||||
|
Spacer: require('../models/layouts/spacer'),
|
||||||
|
WidgetBox: require('../models/layouts/widget_box'),
|
||||||
|
CategoricalMapper: require('../models/mappers/categorical_mapper'),
|
||||||
|
GridMapper: require('../models/mappers/grid_mapper'),
|
||||||
|
LinearColorMapper: require('../models/mappers/linear_color_mapper'),
|
||||||
|
LinearMapper: require('../models/mappers/linear_mapper'),
|
||||||
|
LogColorMapper: require('../models/mappers/log_color_mapper'),
|
||||||
|
LogMapper: require('../models/mappers/log_mapper'),
|
||||||
|
Transform: require('../models/transforms/transform'),
|
||||||
|
Jitter: require('../models/transforms/jitter'),
|
||||||
|
Interpolator: require('../models/transforms/interpolator'),
|
||||||
|
LinearInterpolator: require('../models/transforms/linear_interpolator'),
|
||||||
|
StepInterpolator: require('../models/transforms/step_interpolator'),
|
||||||
|
Asterisk: require('../models/markers/index').Asterisk,
|
||||||
|
CircleCross: require('../models/markers/index').CircleCross,
|
||||||
|
CircleX: require('../models/markers/index').CircleX,
|
||||||
|
Cross: require('../models/markers/index').Cross,
|
||||||
|
Diamond: require('../models/markers/index').Diamond,
|
||||||
|
DiamondCross: require('../models/markers/index').DiamondCross,
|
||||||
|
InvertedTriangle: require('../models/markers/index').InvertedTriangle,
|
||||||
|
Square: require('../models/markers/index').Square,
|
||||||
|
SquareCross: require('../models/markers/index').SquareCross,
|
||||||
|
SquareX: require('../models/markers/index').SquareX,
|
||||||
|
Triangle: require('../models/markers/index').Triangle,
|
||||||
|
X: require('../models/markers/index').X,
|
||||||
|
Plot: require('../models/plots/plot'),
|
||||||
|
GMapPlot: require('../models/plots/gmap_plot'),
|
||||||
|
DataRange1d: require('../models/ranges/data_range1d'),
|
||||||
|
FactorRange: require('../models/ranges/factor_range'),
|
||||||
|
Range1d: require('../models/ranges/range1d'),
|
||||||
|
GlyphRenderer: require('../models/renderers/glyph_renderer'),
|
||||||
|
AjaxDataSource: require('../models/sources/ajax_data_source'),
|
||||||
|
ColumnDataSource: require('../models/sources/column_data_source'),
|
||||||
|
GeoJSONDataSource: require('../models/sources/geojson_data_source'),
|
||||||
|
AdaptiveTicker: require('../models/tickers/adaptive_ticker'),
|
||||||
|
BasicTicker: require('../models/tickers/basic_ticker'),
|
||||||
|
CategoricalTicker: require('../models/tickers/categorical_ticker'),
|
||||||
|
CompositeTicker: require('../models/tickers/composite_ticker'),
|
||||||
|
ContinuousTicker: require('../models/tickers/continuous_ticker'),
|
||||||
|
DatetimeTicker: require('../models/tickers/datetime_ticker'),
|
||||||
|
DaysTicker: require('../models/tickers/days_ticker'),
|
||||||
|
FixedTicker: require('../models/tickers/fixed_ticker'),
|
||||||
|
LogTicker: require('../models/tickers/log_ticker'),
|
||||||
|
MonthsTicker: require('../models/tickers/months_ticker'),
|
||||||
|
SingleIntervalTicker: require('../models/tickers/single_interval_ticker'),
|
||||||
|
YearsTicker: require('../models/tickers/years_ticker'),
|
||||||
|
TileRenderer: require('../models/tiles/tile_renderer'),
|
||||||
|
TileSource: require('../models/tiles/tile_source'),
|
||||||
|
TMSTileSource: require('../models/tiles/tms_tile_source'),
|
||||||
|
WMTSTileSource: require('../models/tiles/wmts_tile_source'),
|
||||||
|
QUADKEYTileSource: require('../models/tiles/quadkey_tile_source'),
|
||||||
|
BBoxTileSource: require('../models/tiles/bbox_tile_source'),
|
||||||
|
DynamicImageRenderer: require('../models/tiles/dynamic_image_renderer'),
|
||||||
|
ImageSource: require('../models/tiles/image_source'),
|
||||||
|
Toolbar: require('../models/tools/toolbar'),
|
||||||
|
ToolbarBox: require('../models/tools/toolbar_box'),
|
||||||
|
ButtonTool: require('../models/tools/button_tool'),
|
||||||
|
ActionTool: require('../models/tools/actions/action_tool'),
|
||||||
|
SaveTool: require('../models/tools/actions/save_tool'),
|
||||||
|
UndoTool: require('../models/tools/actions/undo_tool'),
|
||||||
|
RedoTool: require('../models/tools/actions/redo_tool'),
|
||||||
|
ResetTool: require('../models/tools/actions/reset_tool'),
|
||||||
|
HelpTool: require('../models/tools/actions/help_tool'),
|
||||||
|
BoxSelectTool: require('../models/tools/gestures/box_select_tool'),
|
||||||
|
BoxZoomTool: require('../models/tools/gestures/box_zoom_tool'),
|
||||||
|
GestureTool: require('../models/tools/gestures/gesture_tool'),
|
||||||
|
LassoSelectTool: require('../models/tools/gestures/lasso_select_tool'),
|
||||||
|
PanTool: require('../models/tools/gestures/pan_tool'),
|
||||||
|
PolySelectTool: require('../models/tools/gestures/poly_select_tool'),
|
||||||
|
SelectTool: require('../models/tools/gestures/select_tool'),
|
||||||
|
ResizeTool: require('../models/tools/gestures/resize_tool'),
|
||||||
|
TapTool: require('../models/tools/gestures/tap_tool'),
|
||||||
|
WheelZoomTool: require('../models/tools/gestures/wheel_zoom_tool'),
|
||||||
|
CrosshairTool: require('../models/tools/inspectors/crosshair_tool'),
|
||||||
|
HoverTool: require('../models/tools/inspectors/hover_tool'),
|
||||||
|
InspectTool: require('../models/tools/inspectors/inspect_tool')
|
||||||
|
};
|
|
@ -0,0 +1,128 @@
|
||||||
|
var HasProps, SelectionManager, Selector, _, hittest, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
HasProps = require("../core/has_props");
|
||||||
|
|
||||||
|
logger = require("../core/logging").logger;
|
||||||
|
|
||||||
|
Selector = require("./selector");
|
||||||
|
|
||||||
|
hittest = require("./hittest");
|
||||||
|
|
||||||
|
p = require("../core/properties");
|
||||||
|
|
||||||
|
SelectionManager = (function(superClass) {
|
||||||
|
extend(SelectionManager, superClass);
|
||||||
|
|
||||||
|
function SelectionManager() {
|
||||||
|
return SelectionManager.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectionManager.prototype.type = 'SelectionManager';
|
||||||
|
|
||||||
|
SelectionManager.internal({
|
||||||
|
source: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
SelectionManager.prototype.initialize = function(attrs, options) {
|
||||||
|
SelectionManager.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.selectors = {};
|
||||||
|
this.inspectors = {};
|
||||||
|
return this.last_inspection_was_empty = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectionManager.prototype.select = function(tool, renderer_view, geometry, final, append) {
|
||||||
|
var indices, selector, source;
|
||||||
|
if (append == null) {
|
||||||
|
append = false;
|
||||||
|
}
|
||||||
|
source = this.get('source');
|
||||||
|
if (source !== renderer_view.mget('data_source')) {
|
||||||
|
logger.warn('select called with mis-matched data sources');
|
||||||
|
}
|
||||||
|
indices = renderer_view.hit_test(geometry);
|
||||||
|
if (indices != null) {
|
||||||
|
selector = this._get_selector(renderer_view);
|
||||||
|
selector.update(indices, final, append);
|
||||||
|
this.get('source').set({
|
||||||
|
"selected": selector.get('indices')
|
||||||
|
});
|
||||||
|
source.trigger('select');
|
||||||
|
source.trigger('select-' + renderer_view.mget('id'));
|
||||||
|
return !indices.is_empty();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectionManager.prototype.inspect = function(tool, renderer_view, geometry, data) {
|
||||||
|
var indices, inspector, r_id, source;
|
||||||
|
source = this.get('source');
|
||||||
|
if (source !== renderer_view.mget('data_source')) {
|
||||||
|
logger.warn('inspect called with mis-matched data sources');
|
||||||
|
}
|
||||||
|
indices = renderer_view.hit_test(geometry);
|
||||||
|
if (indices != null) {
|
||||||
|
r_id = renderer_view.model.id;
|
||||||
|
if (indices.is_empty()) {
|
||||||
|
if (this.last_inspection_was_empty[r_id] == null) {
|
||||||
|
this.last_inspection_was_empty[r_id] = false;
|
||||||
|
}
|
||||||
|
if (this.last_inspection_was_empty[r_id]) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.last_inspection_was_empty[r_id] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.last_inspection_was_empty[r_id] = false;
|
||||||
|
}
|
||||||
|
inspector = this._get_inspector(renderer_view);
|
||||||
|
inspector.update(indices, true, false, true);
|
||||||
|
this.get('source').set({
|
||||||
|
"inspected": inspector.get('indices')
|
||||||
|
}, {
|
||||||
|
"silent": true
|
||||||
|
});
|
||||||
|
source.trigger('inspect', indices, tool, renderer_view, source, data);
|
||||||
|
source.trigger("inspect" + (renderer_view.mget('id')), indices, tool, renderer_view, source, data);
|
||||||
|
return !indices.is_empty();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectionManager.prototype.clear = function(rview) {
|
||||||
|
var k, ref, s, selector;
|
||||||
|
if (rview != null) {
|
||||||
|
selector = this._get_selector(rview);
|
||||||
|
selector.clear();
|
||||||
|
} else {
|
||||||
|
ref = this.selectors;
|
||||||
|
for (k in ref) {
|
||||||
|
s = ref[k];
|
||||||
|
s.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.get('source').set({
|
||||||
|
"selected": hittest.create_hit_test_result()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectionManager.prototype._get_selector = function(rview) {
|
||||||
|
_.setdefault(this.selectors, rview.model.id, new Selector());
|
||||||
|
return this.selectors[rview.model.id];
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectionManager.prototype._get_inspector = function(rview) {
|
||||||
|
_.setdefault(this.inspectors, rview.model.id, new Selector());
|
||||||
|
return this.inspectors[rview.model.id];
|
||||||
|
};
|
||||||
|
|
||||||
|
return SelectionManager;
|
||||||
|
|
||||||
|
})(HasProps);
|
||||||
|
|
||||||
|
module.exports = SelectionManager;
|
|
@ -0,0 +1,65 @@
|
||||||
|
var HasProps, Selector, _, hittest, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
HasProps = require("../core/has_props");
|
||||||
|
|
||||||
|
hittest = require("./hittest");
|
||||||
|
|
||||||
|
logger = require("../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../core/properties");
|
||||||
|
|
||||||
|
Selector = (function(superClass) {
|
||||||
|
extend(Selector, superClass);
|
||||||
|
|
||||||
|
function Selector() {
|
||||||
|
return Selector.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector.prototype.type = 'Selector';
|
||||||
|
|
||||||
|
Selector.prototype.update = function(indices, final, append, silent) {
|
||||||
|
if (silent == null) {
|
||||||
|
silent = false;
|
||||||
|
}
|
||||||
|
this.set('timestamp', new Date(), {
|
||||||
|
silent: silent
|
||||||
|
});
|
||||||
|
this.set('final', final, {
|
||||||
|
silent: silent
|
||||||
|
});
|
||||||
|
if (append) {
|
||||||
|
indices['0d'].indices = _.union(this.get('indices')['0d'].indices, indices['0d'].indices);
|
||||||
|
indices['0d'].glyph = this.get('indices')['0d'].glyph || indices['0d'].glyph;
|
||||||
|
indices['1d'].indices = _.union(this.get('indices')['1d'].indices, indices['1d'].indices);
|
||||||
|
indices['2d'].indices = _.union(this.get('indices')['2d'].indices, indices['2d'].indices);
|
||||||
|
}
|
||||||
|
return this.set('indices', indices, {
|
||||||
|
silent: silent
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.clear = function() {
|
||||||
|
this.set('timestamp', new Date());
|
||||||
|
this.set('final', true);
|
||||||
|
return this.set('indices', hittest.create_hit_test_result());
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.internal({
|
||||||
|
indices: [
|
||||||
|
p.Any, function() {
|
||||||
|
return hittest.create_hit_test_result();
|
||||||
|
}
|
||||||
|
],
|
||||||
|
final: [p.Boolean],
|
||||||
|
timestamp: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Selector;
|
||||||
|
|
||||||
|
})(HasProps);
|
||||||
|
|
||||||
|
module.exports = Selector;
|
|
@ -0,0 +1,32 @@
|
||||||
|
var Model, ToolEvents, _, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Model = require("../model");
|
||||||
|
|
||||||
|
logger = require("../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../core/properties");
|
||||||
|
|
||||||
|
ToolEvents = (function(superClass) {
|
||||||
|
extend(ToolEvents, superClass);
|
||||||
|
|
||||||
|
function ToolEvents() {
|
||||||
|
return ToolEvents.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolEvents.prototype.type = 'ToolEvents';
|
||||||
|
|
||||||
|
ToolEvents.define({
|
||||||
|
geometries: [p.Array, []]
|
||||||
|
});
|
||||||
|
|
||||||
|
return ToolEvents;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: ToolEvents
|
||||||
|
};
|
|
@ -0,0 +1,338 @@
|
||||||
|
var $, Backbone, Hammer, UIEvents, logger, mousewheel,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
Hammer = require("hammerjs");
|
||||||
|
|
||||||
|
mousewheel = require("jquery-mousewheel")($);
|
||||||
|
|
||||||
|
logger = require("../core/logging").logger;
|
||||||
|
|
||||||
|
UIEvents = (function(superClass) {
|
||||||
|
extend(UIEvents, superClass);
|
||||||
|
|
||||||
|
function UIEvents() {
|
||||||
|
return UIEvents.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEvents.prototype.initialize = function(attrs, options) {
|
||||||
|
UIEvents.__super__.initialize.call(this, attrs, options);
|
||||||
|
return this._hammer_element();
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._hammer_element = function() {
|
||||||
|
var hit_area;
|
||||||
|
hit_area = this.get('hit_area');
|
||||||
|
this.hammer = new Hammer(hit_area[0]);
|
||||||
|
this.hammer.get('doubletap').recognizeWith('tap');
|
||||||
|
this.hammer.get('tap').requireFailure('doubletap');
|
||||||
|
this.hammer.get('doubletap').dropRequireFailure('tap');
|
||||||
|
this.hammer.on('doubletap', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._doubletap(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('tap', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._tap(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('press', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._press(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.get('pan').set({
|
||||||
|
direction: Hammer.DIRECTION_ALL
|
||||||
|
});
|
||||||
|
this.hammer.on('panstart', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pan_start(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('pan', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pan(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('panend', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pan_end(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.get('pinch').set({
|
||||||
|
enable: true
|
||||||
|
});
|
||||||
|
this.hammer.on('pinchstart', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pinch_start(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('pinch', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pinch(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('pinchend', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._pinch_end(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.get('rotate').set({
|
||||||
|
enable: true
|
||||||
|
});
|
||||||
|
this.hammer.on('rotatestart', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._rotate_start(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('rotate', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._rotate(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.hammer.on('rotateend', (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._rotate_end(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
hit_area.mousemove((function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._mouse_move(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
hit_area.mouseenter((function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._mouse_enter(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
hit_area.mouseleave((function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._mouse_exit(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
hit_area.mousewheel((function(_this) {
|
||||||
|
return function(e, delta) {
|
||||||
|
return _this._mouse_wheel(e, delta);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
$(document).keydown((function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._key_down(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
return $(document).keyup((function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
return _this._key_up(e);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype.register_tool = function(tool_view) {
|
||||||
|
var et, id, type;
|
||||||
|
et = tool_view.model.event_type;
|
||||||
|
id = tool_view.model.id;
|
||||||
|
type = tool_view.model.type;
|
||||||
|
if (et == null) {
|
||||||
|
logger.debug("Button tool: " + type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (et === 'pan' || et === 'pinch' || et === 'rotate') {
|
||||||
|
logger.debug("Registering tool: " + type + " for event '" + et + "'");
|
||||||
|
if (tool_view["_" + et + "_start"] != null) {
|
||||||
|
tool_view.listenTo(this, et + ":start:" + id, tool_view["_" + et + "_start"]);
|
||||||
|
}
|
||||||
|
if (tool_view["_" + et]) {
|
||||||
|
tool_view.listenTo(this, et + ":" + id, tool_view["_" + et]);
|
||||||
|
}
|
||||||
|
if (tool_view["_" + et + "_end"]) {
|
||||||
|
tool_view.listenTo(this, et + ":end:" + id, tool_view["_" + et + "_end"]);
|
||||||
|
}
|
||||||
|
} else if (et === "move") {
|
||||||
|
logger.debug("Registering tool: " + type + " for event '" + et + "'");
|
||||||
|
if (tool_view._move_enter != null) {
|
||||||
|
tool_view.listenTo(this, "move:enter", tool_view._move_enter);
|
||||||
|
}
|
||||||
|
tool_view.listenTo(this, "move", tool_view["_move"]);
|
||||||
|
if (tool_view._move_exit != null) {
|
||||||
|
tool_view.listenTo(this, "move:exit", tool_view._move_exit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug("Registering tool: " + type + " for event '" + et + "'");
|
||||||
|
tool_view.listenTo(this, et + ":" + id, tool_view["_" + et]);
|
||||||
|
}
|
||||||
|
if (tool_view._keydown != null) {
|
||||||
|
logger.debug("Registering tool: " + type + " for event 'keydown'");
|
||||||
|
tool_view.listenTo(this, "keydown", tool_view._keydown);
|
||||||
|
}
|
||||||
|
if (tool_view._keyup != null) {
|
||||||
|
logger.debug("Registering tool: " + type + " for event 'keyup'");
|
||||||
|
tool_view.listenTo(this, "keyup", tool_view._keyup);
|
||||||
|
}
|
||||||
|
if (tool_view._doubletap != null) {
|
||||||
|
logger.debug("Registering tool: " + type + " for event 'doubletap'");
|
||||||
|
tool_view.listenTo(this, "doubletap", tool_view._doubletap);
|
||||||
|
}
|
||||||
|
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
|
||||||
|
if (et === 'pinch') {
|
||||||
|
logger.debug("Registering scroll on touch screen");
|
||||||
|
return tool_view.listenTo(this, "scroll:" + id, tool_view["_scroll"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._trigger = function(event_type, e) {
|
||||||
|
var active_tool, base_event_type, gestures, toolbar;
|
||||||
|
toolbar = this.get('toolbar');
|
||||||
|
base_event_type = event_type.split(":")[0];
|
||||||
|
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
|
||||||
|
if (event_type === 'scroll') {
|
||||||
|
base_event_type = 'pinch';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gestures = toolbar.get('gestures');
|
||||||
|
active_tool = gestures[base_event_type].active;
|
||||||
|
if (active_tool != null) {
|
||||||
|
return this._trigger_event(event_type, active_tool, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._trigger_event = function(event_type, active_tool, e) {
|
||||||
|
if (active_tool.get('active') === true) {
|
||||||
|
if (event_type === 'scroll') {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
return this.trigger(event_type + ":" + active_tool.id, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._bokify_hammer = function(e) {
|
||||||
|
var left, offset, ref, ref1, top, x, y;
|
||||||
|
if (e.pointerType === 'mouse') {
|
||||||
|
x = e.srcEvent.pageX;
|
||||||
|
y = e.srcEvent.pageY;
|
||||||
|
} else {
|
||||||
|
x = e.pointers[0].pageX;
|
||||||
|
y = e.pointers[0].pageY;
|
||||||
|
}
|
||||||
|
offset = $(e.target).offset();
|
||||||
|
left = (ref = offset.left) != null ? ref : 0;
|
||||||
|
top = (ref1 = offset.top) != null ? ref1 : 0;
|
||||||
|
return e.bokeh = {
|
||||||
|
sx: x - left,
|
||||||
|
sy: y - top
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._bokify_jq = function(e) {
|
||||||
|
var left, offset, ref, ref1, top;
|
||||||
|
offset = $(e.currentTarget).offset();
|
||||||
|
left = (ref = offset.left) != null ? ref : 0;
|
||||||
|
top = (ref1 = offset.top) != null ? ref1 : 0;
|
||||||
|
return e.bokeh = {
|
||||||
|
sx: e.pageX - left,
|
||||||
|
sy: e.pageY - top
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._tap = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('tap', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._doubletap = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this.trigger('doubletap', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._press = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('press', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pan_start = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
e.bokeh.sx -= e.deltaX;
|
||||||
|
e.bokeh.sy -= e.deltaY;
|
||||||
|
return this._trigger('pan:start', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pan = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('pan', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pan_end = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('pan:end', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pinch_start = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('pinch:start', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pinch = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('pinch', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._pinch_end = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('pinch:end', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._rotate_start = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('rotate:start', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._rotate = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('rotate', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._rotate_end = function(e) {
|
||||||
|
this._bokify_hammer(e);
|
||||||
|
return this._trigger('rotate:end', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._mouse_enter = function(e) {
|
||||||
|
this._bokify_jq(e);
|
||||||
|
return this.trigger('move:enter', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._mouse_move = function(e) {
|
||||||
|
this._bokify_jq(e);
|
||||||
|
return this.trigger('move', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._mouse_exit = function(e) {
|
||||||
|
this._bokify_jq(e);
|
||||||
|
return this.trigger('move:exit', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._mouse_wheel = function(e, delta) {
|
||||||
|
this._bokify_jq(e);
|
||||||
|
e.bokeh.delta = delta;
|
||||||
|
return this._trigger('scroll', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._key_down = function(e) {
|
||||||
|
return this.trigger('keydown', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEvents.prototype._key_up = function(e) {
|
||||||
|
return this.trigger('keyup', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
return UIEvents;
|
||||||
|
|
||||||
|
})(Backbone.Model);
|
||||||
|
|
||||||
|
module.exports = UIEvents;
|
|
@ -0,0 +1,5 @@
|
||||||
|
var coffee, eco;
|
||||||
|
|
||||||
|
coffee = require("coffee-script");
|
||||||
|
|
||||||
|
eco = require("eco");
|
|
@ -0,0 +1,50 @@
|
||||||
|
var Backbone, BokehView, _,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
BokehView = (function(superClass) {
|
||||||
|
extend(BokehView, superClass);
|
||||||
|
|
||||||
|
function BokehView() {
|
||||||
|
return BokehView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
BokehView.prototype.initialize = function(options) {
|
||||||
|
if (!_.has(options, 'id')) {
|
||||||
|
return this.id = _.uniqueId('BokehView');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BokehView.prototype.bind_bokeh_events = function() {};
|
||||||
|
|
||||||
|
BokehView.prototype.remove = function() {
|
||||||
|
var ref, target, val;
|
||||||
|
if (_.has(this, 'eventers')) {
|
||||||
|
ref = this.eventers;
|
||||||
|
for (target in ref) {
|
||||||
|
if (!hasProp.call(ref, target)) continue;
|
||||||
|
val = ref[target];
|
||||||
|
val.off(null, null, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.trigger('remove', this);
|
||||||
|
return BokehView.__super__.remove.call(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
BokehView.prototype.mget = function() {
|
||||||
|
return this.model.get.apply(this.model, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BokehView.prototype.mset = function() {
|
||||||
|
return this.model.set.apply(this.model, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
return BokehView;
|
||||||
|
|
||||||
|
})(Backbone.View);
|
||||||
|
|
||||||
|
module.exports = BokehView;
|
|
@ -0,0 +1,21 @@
|
||||||
|
module.exports = {
|
||||||
|
AngleUnits: ["deg", "rad"],
|
||||||
|
Dimension: ["width", "height"],
|
||||||
|
Direction: ["clock", "anticlock"],
|
||||||
|
FontStyle: ["normal", "italic", "bold"],
|
||||||
|
LineCap: ["butt", "round", "square"],
|
||||||
|
LineJoin: ["miter", "round", "bevel"],
|
||||||
|
Location: ["above", "below", "left", "right"],
|
||||||
|
LegendLocation: ["top_left", "top_center", "top_right", "left_center", "center", "right_center", "bottom_left", "bottom_center", "bottom_right"],
|
||||||
|
Orientation: ["vertical", "horizontal"],
|
||||||
|
RenderLevel: ["image", "underlay", "glyph", "annotation", "overlay", "tool"],
|
||||||
|
RenderMode: ["canvas", "css"],
|
||||||
|
Side: ["left", "right"],
|
||||||
|
SpatialUnits: ["screen", "data"],
|
||||||
|
StartEnd: ["start", "end"],
|
||||||
|
TextAlign: ["left", "right", "center"],
|
||||||
|
TextBaseline: ["top", "middle", "bottom", "alphabetic", "hanging", "ideographic"],
|
||||||
|
DistributionTypes: ["uniform", "normal"],
|
||||||
|
TransformStepModes: ["after", "before", "center"],
|
||||||
|
SizingMode: ["stretch_both", "scale_width", "scale_height", "scale_both", "fixed"]
|
||||||
|
};
|
|
@ -0,0 +1,553 @@
|
||||||
|
var $, Backbone, HasProps, _, logger, property_mixins, refs,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty,
|
||||||
|
slice = [].slice;
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
logger = require("./logging").logger;
|
||||||
|
|
||||||
|
property_mixins = require("./property_mixins");
|
||||||
|
|
||||||
|
refs = require("./util/refs");
|
||||||
|
|
||||||
|
HasProps = (function(superClass) {
|
||||||
|
extend(HasProps, superClass);
|
||||||
|
|
||||||
|
HasProps.prototype.props = {};
|
||||||
|
|
||||||
|
HasProps.prototype.mixins = [];
|
||||||
|
|
||||||
|
HasProps.define = function(object) {
|
||||||
|
var name, prop, results;
|
||||||
|
results = [];
|
||||||
|
for (name in object) {
|
||||||
|
prop = object[name];
|
||||||
|
results.push((function(_this) {
|
||||||
|
return function(name, prop) {
|
||||||
|
var default_value, internal, props, refined_prop, type;
|
||||||
|
if (_this.prototype.props[name] != null) {
|
||||||
|
throw new Error("attempted to redefine property '" + _this.name + "." + name + "'");
|
||||||
|
}
|
||||||
|
if ((_this.prototype[name] != null) && name !== "url") {
|
||||||
|
throw new Error("attempted to redefine attribute '" + _this.name + "." + name + "'");
|
||||||
|
}
|
||||||
|
Object.defineProperty(_this.prototype, name, {
|
||||||
|
get: function() {
|
||||||
|
return this.get(name);
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
return this.set(name, value);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
configurable: false,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
type = prop[0], default_value = prop[1], internal = prop[2];
|
||||||
|
refined_prop = {
|
||||||
|
type: type,
|
||||||
|
default_value: default_value,
|
||||||
|
internal: internal != null ? internal : false
|
||||||
|
};
|
||||||
|
props = _.clone(_this.prototype.props);
|
||||||
|
props[name] = refined_prop;
|
||||||
|
return _this.prototype.props = props;
|
||||||
|
};
|
||||||
|
})(this)(name, prop));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.internal = function(object) {
|
||||||
|
var _object, fn, name, prop;
|
||||||
|
_object = {};
|
||||||
|
fn = (function(_this) {
|
||||||
|
return function(name, prop) {
|
||||||
|
var default_value, type;
|
||||||
|
type = prop[0], default_value = prop[1];
|
||||||
|
return _object[name] = [type, default_value, true];
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
for (name in object) {
|
||||||
|
prop = object[name];
|
||||||
|
fn(name, prop);
|
||||||
|
}
|
||||||
|
return this.define(_object);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.mixin = function() {
|
||||||
|
var mixins, names;
|
||||||
|
names = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
this.define(property_mixins.create(names));
|
||||||
|
mixins = this.prototype.mixins.concat(names);
|
||||||
|
return this.prototype.mixins = mixins;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.mixins = function(names) {
|
||||||
|
return this.mixin.apply(this, names);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.override = function(name_or_object, default_value) {
|
||||||
|
var name, object, results;
|
||||||
|
if (_.isString(name_or_object)) {
|
||||||
|
object = {};
|
||||||
|
object[name] = default_value;
|
||||||
|
} else {
|
||||||
|
object = name_or_object;
|
||||||
|
}
|
||||||
|
results = [];
|
||||||
|
for (name in object) {
|
||||||
|
default_value = object[name];
|
||||||
|
results.push((function(_this) {
|
||||||
|
return function(name, default_value) {
|
||||||
|
var props, value;
|
||||||
|
value = _this.prototype.props[name];
|
||||||
|
if (value == null) {
|
||||||
|
throw new Error("attempted to override nonexistent '" + _this.name + "." + name + "'");
|
||||||
|
}
|
||||||
|
props = _.clone(_this.prototype.props);
|
||||||
|
props[name] = _.extend({}, value, {
|
||||||
|
default_value: default_value
|
||||||
|
});
|
||||||
|
return _this.prototype.props = props;
|
||||||
|
};
|
||||||
|
})(this)(name, default_value));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.toString = function() {
|
||||||
|
return this.type + "(" + this.id + ")";
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.destroy = function(options) {
|
||||||
|
HasProps.__super__.destroy.call(this, options);
|
||||||
|
return this.stopListening();
|
||||||
|
};
|
||||||
|
|
||||||
|
function HasProps(attributes, options) {
|
||||||
|
var attrs, default_value, name, ref, ref1, type;
|
||||||
|
this.document = null;
|
||||||
|
attrs = attributes || {};
|
||||||
|
if (!options) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
this.cid = _.uniqueId('c');
|
||||||
|
this.attributes = {};
|
||||||
|
this.properties = {};
|
||||||
|
ref = this.props;
|
||||||
|
for (name in ref) {
|
||||||
|
ref1 = ref[name], type = ref1.type, default_value = ref1.default_value;
|
||||||
|
if (type == null) {
|
||||||
|
throw new Error("undefined property type for " + this.type + "." + name);
|
||||||
|
}
|
||||||
|
this.properties[name] = new type({
|
||||||
|
obj: this,
|
||||||
|
attr: name,
|
||||||
|
default_value: default_value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (options.parse) {
|
||||||
|
attrs = this.parse(attrs, options) || {};
|
||||||
|
}
|
||||||
|
this._set_after_defaults = {};
|
||||||
|
this.set(attrs, options);
|
||||||
|
this.changed = {};
|
||||||
|
this._computed = {};
|
||||||
|
if (!_.has(attrs, this.idAttribute)) {
|
||||||
|
this.id = _.uniqueId(this.type);
|
||||||
|
this.attributes[this.idAttribute] = this.id;
|
||||||
|
}
|
||||||
|
if (!options.defer_initialization) {
|
||||||
|
this.initialize.apply(this, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HasProps.prototype.set = function(key, value, options) {
|
||||||
|
var attrs, old, prop_name, results, val;
|
||||||
|
if (_.isObject(key) || key === null) {
|
||||||
|
attrs = key;
|
||||||
|
options = value;
|
||||||
|
} else {
|
||||||
|
attrs = {};
|
||||||
|
attrs[key] = value;
|
||||||
|
}
|
||||||
|
for (key in attrs) {
|
||||||
|
if (!hasProp.call(attrs, key)) continue;
|
||||||
|
val = attrs[key];
|
||||||
|
prop_name = key;
|
||||||
|
if (!(prop_name === "id" || this.props[prop_name])) {
|
||||||
|
throw new Error(this.type + ".set('" + prop_name + "'): " + prop_name + " wasn't declared");
|
||||||
|
}
|
||||||
|
if (!((options != null) && options.defaults)) {
|
||||||
|
this._set_after_defaults[key] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_.isEmpty(attrs)) {
|
||||||
|
old = {};
|
||||||
|
for (key in attrs) {
|
||||||
|
value = attrs[key];
|
||||||
|
old[key] = this.get(key);
|
||||||
|
}
|
||||||
|
HasProps.__super__.set.call(this, attrs, options);
|
||||||
|
if ((options != null ? options.silent : void 0) == null) {
|
||||||
|
results = [];
|
||||||
|
for (key in attrs) {
|
||||||
|
value = attrs[key];
|
||||||
|
results.push(this._tell_document_about_change(key, old[key], this.get(key)));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.add_dependencies = function(prop_name, object, fields) {
|
||||||
|
var fld, j, len, prop_spec, results;
|
||||||
|
if (!_.isArray(fields)) {
|
||||||
|
fields = [fields];
|
||||||
|
}
|
||||||
|
prop_spec = this._computed[prop_name];
|
||||||
|
prop_spec.dependencies = prop_spec.dependencies.concat({
|
||||||
|
obj: object,
|
||||||
|
fields: fields
|
||||||
|
});
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = fields.length; j < len; j++) {
|
||||||
|
fld = fields[j];
|
||||||
|
results.push(this.listenTo(object, "change:" + fld, prop_spec['callbacks']['changedep']));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.define_computed_property = function(prop_name, getter, use_cache) {
|
||||||
|
var changedep, prop_spec, propchange;
|
||||||
|
if (use_cache == null) {
|
||||||
|
use_cache = true;
|
||||||
|
}
|
||||||
|
if (this.props[prop_name] != null) {
|
||||||
|
console.log("attempted to redefine existing property " + this.type + "." + prop_name);
|
||||||
|
}
|
||||||
|
if (_.has(this._computed, prop_name)) {
|
||||||
|
throw new Error("attempted to redefine existing computed property " + this.type + "." + prop_name);
|
||||||
|
}
|
||||||
|
changedep = (function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.trigger('changedep:' + prop_name);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
propchange = (function(_this) {
|
||||||
|
return function() {
|
||||||
|
var firechange, new_val, old_val;
|
||||||
|
firechange = true;
|
||||||
|
if (prop_spec['use_cache']) {
|
||||||
|
old_val = prop_spec.cache;
|
||||||
|
prop_spec.cache = void 0;
|
||||||
|
new_val = _this.get(prop_name);
|
||||||
|
firechange = new_val !== old_val;
|
||||||
|
}
|
||||||
|
if (firechange) {
|
||||||
|
_this.trigger('change:' + prop_name, _this, _this.get(prop_name));
|
||||||
|
return _this.trigger('change', _this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
prop_spec = {
|
||||||
|
'getter': getter,
|
||||||
|
'dependencies': [],
|
||||||
|
'use_cache': use_cache,
|
||||||
|
'callbacks': {
|
||||||
|
changedep: changedep,
|
||||||
|
propchange: propchange
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._computed[prop_name] = prop_spec;
|
||||||
|
this.listenTo(this, "changedep:" + prop_name, prop_spec['callbacks']['propchange']);
|
||||||
|
return prop_spec;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.override_computed_property = function(prop_name, getter, use_cache) {
|
||||||
|
if (use_cache == null) {
|
||||||
|
use_cache = true;
|
||||||
|
}
|
||||||
|
if (_.has(this._computed, prop_name)) {
|
||||||
|
this._remove_computed_property(prop_name);
|
||||||
|
}
|
||||||
|
return this.define_computed_property(prop_name, getter, use_cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype._remove_computed_property = function(prop_name) {
|
||||||
|
var dep, dependencies, fld, j, l, len, len1, obj, prop_spec, ref;
|
||||||
|
prop_spec = this._computed[prop_name];
|
||||||
|
dependencies = prop_spec.dependencies;
|
||||||
|
for (j = 0, len = dependencies.length; j < len; j++) {
|
||||||
|
dep = dependencies[j];
|
||||||
|
obj = dep.obj;
|
||||||
|
ref = dep['fields'];
|
||||||
|
for (l = 0, len1 = ref.length; l < len1; l++) {
|
||||||
|
fld = ref[l];
|
||||||
|
obj.off('change:' + fld, prop_spec['callbacks']['changedep'], this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.off("changedep:" + dep);
|
||||||
|
return delete this._computed[prop_name];
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.get = function(prop_name) {
|
||||||
|
if (_.has(this._computed, prop_name)) {
|
||||||
|
return this._get_prop(prop_name);
|
||||||
|
} else {
|
||||||
|
if (!(prop_name === "id" || this.props[prop_name])) {
|
||||||
|
throw new Error(this.type + ".get('" + prop_name + "'): " + prop_name + " wasn't declared");
|
||||||
|
}
|
||||||
|
return HasProps.__super__.get.call(this, prop_name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype._get_prop = function(prop_name) {
|
||||||
|
var computed, getter, prop_spec;
|
||||||
|
prop_spec = this._computed[prop_name];
|
||||||
|
if (prop_spec.use_cache && prop_spec.cache) {
|
||||||
|
return prop_spec.cache;
|
||||||
|
} else {
|
||||||
|
getter = prop_spec.getter;
|
||||||
|
computed = getter.apply(this, [prop_name]);
|
||||||
|
if (prop_spec.use_cache) {
|
||||||
|
prop_spec.cache = computed;
|
||||||
|
}
|
||||||
|
return computed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.ref = function() {
|
||||||
|
return refs.create_ref(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.set_subtype = function(subtype) {
|
||||||
|
return this._subtype = subtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.sync = function(method, model, options) {
|
||||||
|
return options.success(model.attributes, null, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.defaults = function() {
|
||||||
|
throw new Error("don't use HasProps.defaults anymore");
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.attribute_is_serializable = function(attr) {
|
||||||
|
var prop;
|
||||||
|
if (attr === "id") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prop = this.props[attr];
|
||||||
|
if (prop == null) {
|
||||||
|
throw new Error(this.type + ".attribute_is_serializable('" + attr + "'): " + attr + " wasn't declared");
|
||||||
|
}
|
||||||
|
return !prop.internal;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.serializable_attributes = function() {
|
||||||
|
var attrs, name, ref, value;
|
||||||
|
attrs = {};
|
||||||
|
ref = this.attributes;
|
||||||
|
for (name in ref) {
|
||||||
|
value = ref[name];
|
||||||
|
if (this.attribute_is_serializable(name)) {
|
||||||
|
attrs[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.toJSON = function(options) {
|
||||||
|
throw new Error("bug: toJSON should not be called on " + this + ", models require special serialization measures");
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps._value_to_json = function(key, value, optional_parent_object) {
|
||||||
|
var i, j, len, ref_array, ref_obj, subkey, v;
|
||||||
|
if (value instanceof HasProps) {
|
||||||
|
return value.ref();
|
||||||
|
} else if (_.isArray(value)) {
|
||||||
|
ref_array = [];
|
||||||
|
for (i = j = 0, len = value.length; j < len; i = ++j) {
|
||||||
|
v = value[i];
|
||||||
|
ref_array.push(HasProps._value_to_json(i, v, value));
|
||||||
|
}
|
||||||
|
return ref_array;
|
||||||
|
} else if (_.isObject(value)) {
|
||||||
|
ref_obj = {};
|
||||||
|
for (subkey in value) {
|
||||||
|
if (!hasProp.call(value, subkey)) continue;
|
||||||
|
ref_obj[subkey] = HasProps._value_to_json(subkey, value[subkey], value);
|
||||||
|
}
|
||||||
|
return ref_obj;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.attributes_as_json = function(include_defaults, value_to_json) {
|
||||||
|
var attrs, key, ref, value;
|
||||||
|
if (include_defaults == null) {
|
||||||
|
include_defaults = true;
|
||||||
|
}
|
||||||
|
if (value_to_json == null) {
|
||||||
|
value_to_json = HasProps._value_to_json;
|
||||||
|
}
|
||||||
|
attrs = {};
|
||||||
|
ref = this.serializable_attributes();
|
||||||
|
for (key in ref) {
|
||||||
|
if (!hasProp.call(ref, key)) continue;
|
||||||
|
value = ref[key];
|
||||||
|
if (include_defaults) {
|
||||||
|
attrs[key] = value;
|
||||||
|
} else if (key in this._set_after_defaults) {
|
||||||
|
attrs[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value_to_json("attributes", attrs, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps._json_record_references = function(doc, v, result, recurse) {
|
||||||
|
var elem, j, k, len, model, results, results1;
|
||||||
|
if (v === null) {
|
||||||
|
|
||||||
|
} else if (refs.is_ref(v)) {
|
||||||
|
if (!(v.id in result)) {
|
||||||
|
model = doc.get_model_by_id(v.id);
|
||||||
|
return HasProps._value_record_references(model, result, recurse);
|
||||||
|
}
|
||||||
|
} else if (_.isArray(v)) {
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = v.length; j < len; j++) {
|
||||||
|
elem = v[j];
|
||||||
|
results.push(HasProps._json_record_references(doc, elem, result, recurse));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} else if (_.isObject(v)) {
|
||||||
|
results1 = [];
|
||||||
|
for (k in v) {
|
||||||
|
if (!hasProp.call(v, k)) continue;
|
||||||
|
elem = v[k];
|
||||||
|
results1.push(HasProps._json_record_references(doc, elem, result, recurse));
|
||||||
|
}
|
||||||
|
return results1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps._value_record_references = function(v, result, recurse) {
|
||||||
|
var elem, immediate, j, k, l, len, len1, obj, results, results1, results2;
|
||||||
|
if (v === null) {
|
||||||
|
|
||||||
|
} else if (v instanceof HasProps) {
|
||||||
|
if (!(v.id in result)) {
|
||||||
|
result[v.id] = v;
|
||||||
|
if (recurse) {
|
||||||
|
immediate = v._immediate_references();
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = immediate.length; j < len; j++) {
|
||||||
|
obj = immediate[j];
|
||||||
|
results.push(HasProps._value_record_references(obj, result, true));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (_.isArray(v)) {
|
||||||
|
results1 = [];
|
||||||
|
for (l = 0, len1 = v.length; l < len1; l++) {
|
||||||
|
elem = v[l];
|
||||||
|
results1.push(HasProps._value_record_references(elem, result, recurse));
|
||||||
|
}
|
||||||
|
return results1;
|
||||||
|
} else if (_.isObject(v)) {
|
||||||
|
results2 = [];
|
||||||
|
for (k in v) {
|
||||||
|
if (!hasProp.call(v, k)) continue;
|
||||||
|
elem = v[k];
|
||||||
|
results2.push(HasProps._value_record_references(elem, result, recurse));
|
||||||
|
}
|
||||||
|
return results2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype._immediate_references = function() {
|
||||||
|
var attrs, key, result, value;
|
||||||
|
result = {};
|
||||||
|
attrs = this.serializable_attributes();
|
||||||
|
for (key in attrs) {
|
||||||
|
value = attrs[key];
|
||||||
|
HasProps._value_record_references(value, result, false);
|
||||||
|
}
|
||||||
|
return _.values(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.references = function() {
|
||||||
|
var references;
|
||||||
|
references = {};
|
||||||
|
HasProps._value_record_references(this, references, true);
|
||||||
|
return _.values(references);
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.attach_document = function(doc) {
|
||||||
|
var name, prop, ref;
|
||||||
|
if (this.document !== null && this.document !== doc) {
|
||||||
|
throw new Error("models must be owned by only a single document");
|
||||||
|
}
|
||||||
|
this.document = doc;
|
||||||
|
ref = this.properties;
|
||||||
|
for (name in ref) {
|
||||||
|
prop = ref[name];
|
||||||
|
prop.update();
|
||||||
|
}
|
||||||
|
if (this._doc_attached != null) {
|
||||||
|
return this._doc_attached();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype.detach_document = function() {
|
||||||
|
return this.document = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasProps.prototype._tell_document_about_change = function(attr, old, new_) {
|
||||||
|
var need_invalidate, new_id, new_ref, new_refs, old_id, old_ref, old_refs;
|
||||||
|
if (!this.attribute_is_serializable(attr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.document !== null) {
|
||||||
|
new_refs = {};
|
||||||
|
HasProps._value_record_references(new_, new_refs, false);
|
||||||
|
old_refs = {};
|
||||||
|
HasProps._value_record_references(old, old_refs, false);
|
||||||
|
need_invalidate = false;
|
||||||
|
for (new_id in new_refs) {
|
||||||
|
new_ref = new_refs[new_id];
|
||||||
|
if (!(new_id in old_refs)) {
|
||||||
|
need_invalidate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!need_invalidate) {
|
||||||
|
for (old_id in old_refs) {
|
||||||
|
old_ref = old_refs[old_id];
|
||||||
|
if (!(old_id in new_refs)) {
|
||||||
|
need_invalidate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (need_invalidate) {
|
||||||
|
this.document._invalidate_all_models();
|
||||||
|
}
|
||||||
|
return this.document._notify_change(this, attr, old, new_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return HasProps;
|
||||||
|
|
||||||
|
})(Backbone.Model);
|
||||||
|
|
||||||
|
module.exports = HasProps;
|
|
@ -0,0 +1,78 @@
|
||||||
|
var EQ, GE, LayoutCanvas, Model, Strength, Variable, _, p, ref,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
ref = require("./solver"), Variable = ref.Variable, EQ = ref.EQ, GE = ref.GE, Strength = ref.Strength;
|
||||||
|
|
||||||
|
Model = require("../../model");
|
||||||
|
|
||||||
|
p = require("../properties");
|
||||||
|
|
||||||
|
LayoutCanvas = (function(superClass) {
|
||||||
|
extend(LayoutCanvas, superClass);
|
||||||
|
|
||||||
|
function LayoutCanvas() {
|
||||||
|
return LayoutCanvas.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutCanvas.prototype.type = 'LayoutCanvas';
|
||||||
|
|
||||||
|
LayoutCanvas.prototype.initialize = function(attrs, options) {
|
||||||
|
LayoutCanvas.__super__.initialize.call(this, attrs, options);
|
||||||
|
this._top = new Variable("top " + this.id);
|
||||||
|
this._left = new Variable("left " + this.id);
|
||||||
|
this._width = new Variable("width " + this.id);
|
||||||
|
this._height = new Variable("height " + this.id);
|
||||||
|
this._right = new Variable("right " + this.id);
|
||||||
|
this._bottom = new Variable("bottom " + this.id);
|
||||||
|
this.define_computed_property('height', this._get_var, false);
|
||||||
|
this.define_computed_property('width', this._get_var, false);
|
||||||
|
this.define_computed_property('right', this._get_var, false);
|
||||||
|
this.define_computed_property('left', this._get_var, false);
|
||||||
|
this.define_computed_property('top', this._get_var, false);
|
||||||
|
return this.define_computed_property('bottom', this._get_var, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
LayoutCanvas.internal({
|
||||||
|
layout_location: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
LayoutCanvas.prototype.get_edit_variables = function() {
|
||||||
|
var editables;
|
||||||
|
editables = [];
|
||||||
|
editables.push({
|
||||||
|
edit_variable: this._top,
|
||||||
|
strength: Strength.strong
|
||||||
|
});
|
||||||
|
editables.push({
|
||||||
|
edit_variable: this._left,
|
||||||
|
strength: Strength.strong
|
||||||
|
});
|
||||||
|
editables.push({
|
||||||
|
edit_variable: this._width,
|
||||||
|
strength: Strength.strong
|
||||||
|
});
|
||||||
|
editables.push({
|
||||||
|
edit_variable: this._height,
|
||||||
|
strength: Strength.strong
|
||||||
|
});
|
||||||
|
return editables;
|
||||||
|
};
|
||||||
|
|
||||||
|
LayoutCanvas.prototype.get_constraints = function() {
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
LayoutCanvas.prototype._get_var = function(prop_name) {
|
||||||
|
return this['_' + prop_name].value();
|
||||||
|
};
|
||||||
|
|
||||||
|
return LayoutCanvas;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: LayoutCanvas
|
||||||
|
};
|
|
@ -0,0 +1,262 @@
|
||||||
|
var ALPHABETIC, BOTTOM, CENTER, EQ, GE, HANGING, LEFT, LayoutCanvas, MIDDLE, RIGHT, SidePanel, TOP, _, _align_lookup, _align_lookup_negative, _align_lookup_positive, _angle_lookup, _baseline_lookup, logger, p, pi2, ref, update_constraints,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
ref = require("./solver"), EQ = ref.EQ, GE = ref.GE;
|
||||||
|
|
||||||
|
LayoutCanvas = require("./layout_canvas");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
pi2 = Math.PI / 2;
|
||||||
|
|
||||||
|
ALPHABETIC = 'alphabetic';
|
||||||
|
|
||||||
|
TOP = 'top';
|
||||||
|
|
||||||
|
BOTTOM = 'bottom';
|
||||||
|
|
||||||
|
MIDDLE = 'middle';
|
||||||
|
|
||||||
|
HANGING = 'hanging';
|
||||||
|
|
||||||
|
LEFT = 'left';
|
||||||
|
|
||||||
|
RIGHT = 'right';
|
||||||
|
|
||||||
|
CENTER = 'center';
|
||||||
|
|
||||||
|
_angle_lookup = {
|
||||||
|
above: {
|
||||||
|
parallel: 0,
|
||||||
|
normal: -pi2,
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: -pi2
|
||||||
|
},
|
||||||
|
below: {
|
||||||
|
parallel: 0,
|
||||||
|
normal: pi2,
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: pi2
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
parallel: -pi2,
|
||||||
|
normal: 0,
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: -pi2
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
parallel: pi2,
|
||||||
|
normal: 0,
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: pi2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_baseline_lookup = {
|
||||||
|
above: {
|
||||||
|
justified: TOP,
|
||||||
|
parallel: ALPHABETIC,
|
||||||
|
normal: MIDDLE,
|
||||||
|
horizontal: ALPHABETIC,
|
||||||
|
vertical: MIDDLE
|
||||||
|
},
|
||||||
|
below: {
|
||||||
|
justified: BOTTOM,
|
||||||
|
parallel: HANGING,
|
||||||
|
normal: MIDDLE,
|
||||||
|
horizontal: HANGING,
|
||||||
|
vertical: MIDDLE
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
justified: TOP,
|
||||||
|
parallel: ALPHABETIC,
|
||||||
|
normal: MIDDLE,
|
||||||
|
horizontal: MIDDLE,
|
||||||
|
vertical: ALPHABETIC
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
justified: TOP,
|
||||||
|
parallel: ALPHABETIC,
|
||||||
|
normal: MIDDLE,
|
||||||
|
horizontal: MIDDLE,
|
||||||
|
vertical: ALPHABETIC
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_align_lookup = {
|
||||||
|
above: {
|
||||||
|
justified: CENTER,
|
||||||
|
parallel: CENTER,
|
||||||
|
normal: LEFT,
|
||||||
|
horizontal: CENTER,
|
||||||
|
vertical: LEFT
|
||||||
|
},
|
||||||
|
below: {
|
||||||
|
justified: CENTER,
|
||||||
|
parallel: CENTER,
|
||||||
|
normal: LEFT,
|
||||||
|
horizontal: CENTER,
|
||||||
|
vertical: RIGHT
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
justified: CENTER,
|
||||||
|
parallel: CENTER,
|
||||||
|
normal: RIGHT,
|
||||||
|
horizontal: RIGHT,
|
||||||
|
vertical: CENTER
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
justified: CENTER,
|
||||||
|
parallel: CENTER,
|
||||||
|
normal: LEFT,
|
||||||
|
horizontal: LEFT,
|
||||||
|
vertical: CENTER
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_align_lookup_negative = {
|
||||||
|
above: RIGHT,
|
||||||
|
below: LEFT,
|
||||||
|
left: RIGHT,
|
||||||
|
right: LEFT
|
||||||
|
};
|
||||||
|
|
||||||
|
_align_lookup_positive = {
|
||||||
|
above: LEFT,
|
||||||
|
below: RIGHT,
|
||||||
|
left: RIGHT,
|
||||||
|
right: LEFT
|
||||||
|
};
|
||||||
|
|
||||||
|
update_constraints = function(view) {
|
||||||
|
var s, side, size, v;
|
||||||
|
v = view;
|
||||||
|
if (v.model.props.visible != null) {
|
||||||
|
if (v.mget('visible') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = v._get_size();
|
||||||
|
if (v._last_size == null) {
|
||||||
|
v._last_size = -1;
|
||||||
|
}
|
||||||
|
if (size === v._last_size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = v.model.document.solver();
|
||||||
|
v._last_size = size;
|
||||||
|
if (v._size_constraint != null) {
|
||||||
|
s.remove_constraint(v._size_constraint);
|
||||||
|
}
|
||||||
|
v._size_constraint = GE(v.model.panel._size, -size);
|
||||||
|
s.add_constraint(v._size_constraint);
|
||||||
|
if (v._full_set == null) {
|
||||||
|
v._full_set = false;
|
||||||
|
}
|
||||||
|
if (!v._full_set) {
|
||||||
|
side = v.model.panel.get('side');
|
||||||
|
if (side === 'above' || side === 'below') {
|
||||||
|
s.add_constraint(EQ(v.model.panel._width, [-1, v.plot_model.canvas._width]));
|
||||||
|
}
|
||||||
|
if (side === 'left' || side === 'right') {
|
||||||
|
s.add_constraint(EQ(v.model.panel._height, [-1, v.plot_model.canvas._height]));
|
||||||
|
}
|
||||||
|
return v._full_set = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SidePanel = (function(superClass) {
|
||||||
|
extend(SidePanel, superClass);
|
||||||
|
|
||||||
|
function SidePanel() {
|
||||||
|
return SidePanel.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
SidePanel.internal({
|
||||||
|
side: [p.String],
|
||||||
|
plot: [p.Instance]
|
||||||
|
});
|
||||||
|
|
||||||
|
SidePanel.prototype.initialize = function(attrs, options) {
|
||||||
|
var side;
|
||||||
|
SidePanel.__super__.initialize.call(this, attrs, options);
|
||||||
|
side = this.get('side');
|
||||||
|
if (side === "above") {
|
||||||
|
this._dim = 0;
|
||||||
|
this._normals = [0, -1];
|
||||||
|
this._size = this._height;
|
||||||
|
return this._anchor = this._bottom;
|
||||||
|
} else if (side === "below") {
|
||||||
|
this._dim = 0;
|
||||||
|
this._normals = [0, 1];
|
||||||
|
this._size = this._height;
|
||||||
|
return this._anchor = this._top;
|
||||||
|
} else if (side === "left") {
|
||||||
|
this._dim = 1;
|
||||||
|
this._normals = [-1, 0];
|
||||||
|
this._size = this._width;
|
||||||
|
return this._anchor = this._right;
|
||||||
|
} else if (side === "right") {
|
||||||
|
this._dim = 1;
|
||||||
|
this._normals = [1, 0];
|
||||||
|
this._size = this._width;
|
||||||
|
return this._anchor = this._left;
|
||||||
|
} else {
|
||||||
|
return logger.error("unrecognized side: '" + side + "'");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SidePanel.prototype.get_constraints = function() {
|
||||||
|
var constraints;
|
||||||
|
constraints = [];
|
||||||
|
constraints.push(GE(this._top));
|
||||||
|
constraints.push(GE(this._bottom));
|
||||||
|
constraints.push(GE(this._left));
|
||||||
|
constraints.push(GE(this._right));
|
||||||
|
constraints.push(GE(this._width));
|
||||||
|
constraints.push(GE(this._height));
|
||||||
|
constraints.push(EQ(this._left, this._width, [-1, this._right]));
|
||||||
|
constraints.push(EQ(this._bottom, this._height, [-1, this._top]));
|
||||||
|
return constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
SidePanel.prototype.apply_label_text_heuristics = function(ctx, orient) {
|
||||||
|
var align, baseline, side;
|
||||||
|
side = this.get('side');
|
||||||
|
if (_.isString(orient)) {
|
||||||
|
baseline = _baseline_lookup[side][orient];
|
||||||
|
align = _align_lookup[side][orient];
|
||||||
|
} else if (orient === 0) {
|
||||||
|
baseline = _baseline_lookup[side][orient];
|
||||||
|
align = _align_lookup[side][orient];
|
||||||
|
} else if (orient < 0) {
|
||||||
|
baseline = 'middle';
|
||||||
|
align = _align_lookup_negative[side];
|
||||||
|
} else if (orient > 0) {
|
||||||
|
baseline = 'middle';
|
||||||
|
align = _align_lookup_positive[side];
|
||||||
|
}
|
||||||
|
ctx.textBaseline = baseline;
|
||||||
|
ctx.textAlign = align;
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
SidePanel.prototype.get_label_angle_heuristic = function(orient) {
|
||||||
|
var side;
|
||||||
|
side = this.get('side');
|
||||||
|
return _angle_lookup[side][orient];
|
||||||
|
};
|
||||||
|
|
||||||
|
return SidePanel;
|
||||||
|
|
||||||
|
})(LayoutCanvas.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: SidePanel,
|
||||||
|
update_constraints: update_constraints
|
||||||
|
};
|
|
@ -0,0 +1,104 @@
|
||||||
|
var Backbone, Constraint, Expression, Operator, Solver, Strength, Variable, _, _constrainer, _weak_constrainer, kiwi;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
kiwi = require("kiwi");
|
||||||
|
|
||||||
|
Variable = kiwi.Variable, Expression = kiwi.Expression, Constraint = kiwi.Constraint, Operator = kiwi.Operator, Strength = kiwi.Strength;
|
||||||
|
|
||||||
|
_constrainer = function(op) {
|
||||||
|
return (function(_this) {
|
||||||
|
return function() {
|
||||||
|
var expr;
|
||||||
|
expr = Object.create(Expression.prototype);
|
||||||
|
Expression.apply(expr, arguments);
|
||||||
|
return new Constraint(expr, op);
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
_weak_constrainer = function(op) {
|
||||||
|
return function() {
|
||||||
|
var arg, args, i, len;
|
||||||
|
args = [null];
|
||||||
|
for (i = 0, len = arguments.length; i < len; i++) {
|
||||||
|
arg = arguments[i];
|
||||||
|
args.push(arg);
|
||||||
|
}
|
||||||
|
return new Constraint(new (Function.prototype.bind.apply(Expression, args)), op, kiwi.Strength.weak);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver = (function() {
|
||||||
|
function Solver() {
|
||||||
|
this.solver = new kiwi.Solver();
|
||||||
|
}
|
||||||
|
|
||||||
|
Solver.prototype.clear = function() {
|
||||||
|
return this.solver = new kiwi.Solver();
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.toString = function() {
|
||||||
|
return "Solver[num_constraints=" + (this.num_constraints()) + ", num_edit_variables=" + (this.num_edit_variables()) + "]";
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.num_constraints = function() {
|
||||||
|
return this.solver._cnMap._array.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.num_edit_variables = function() {
|
||||||
|
return this.solver._editMap._array.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.update_variables = function(trigger) {
|
||||||
|
if (trigger == null) {
|
||||||
|
trigger = true;
|
||||||
|
}
|
||||||
|
this.solver.updateVariables();
|
||||||
|
if (trigger) {
|
||||||
|
return this.trigger('layout_update');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.add_constraint = function(constraint) {
|
||||||
|
return this.solver.addConstraint(constraint);
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.remove_constraint = function(constraint) {
|
||||||
|
return this.solver.removeConstraint(constraint);
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.add_edit_variable = function(variable, strength) {
|
||||||
|
return this.solver.addEditVariable(variable, strength);
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.remove_edit_variable = function(variable) {
|
||||||
|
return this.solver.removeEditVariable(variable, strength);
|
||||||
|
};
|
||||||
|
|
||||||
|
Solver.prototype.suggest_value = function(variable, value) {
|
||||||
|
return this.solver.suggestValue(variable, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Solver;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
_.extend(Solver.prototype, Backbone.Events);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Variable: Variable,
|
||||||
|
Expression: Expression,
|
||||||
|
Constraint: Constraint,
|
||||||
|
Operator: Operator,
|
||||||
|
Strength: Strength,
|
||||||
|
EQ: _constrainer(Operator.Eq),
|
||||||
|
LE: _constrainer(Operator.Le),
|
||||||
|
GE: _constrainer(Operator.Ge),
|
||||||
|
WEAK_EQ: _weak_constrainer(Operator.Eq),
|
||||||
|
WEAK_LE: _weak_constrainer(Operator.Le),
|
||||||
|
WEAK_GE: _weak_constrainer(Operator.Ge),
|
||||||
|
Solver: Solver
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
var JL, levels, logger, set_log_level;
|
||||||
|
|
||||||
|
JL = require("jsnlog").JL;
|
||||||
|
|
||||||
|
logger = JL("Bokeh");
|
||||||
|
|
||||||
|
logger.setOptions({
|
||||||
|
"appenders": [JL.createConsoleAppender('consoleAppender')],
|
||||||
|
"level": JL.getInfoLevel()
|
||||||
|
});
|
||||||
|
|
||||||
|
levels = {
|
||||||
|
"trace": JL.getTraceLevel(),
|
||||||
|
"debug": JL.getDebugLevel(),
|
||||||
|
"info": JL.getInfoLevel(),
|
||||||
|
"warn": JL.getWarnLevel(),
|
||||||
|
"error": JL.getErrorLevel(),
|
||||||
|
"fatal": JL.getFatalLevel()
|
||||||
|
};
|
||||||
|
|
||||||
|
set_log_level = function(level) {
|
||||||
|
if (!(level in levels)) {
|
||||||
|
console.log("Bokeh: Unrecognized logging level '" + level + "' passed to Bokeh.set_log_level, ignoring.");
|
||||||
|
console.log("Bokeh: Valid log levels are: " + (Object.keys(levels)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Bokeh: setting log level to: '" + level + "'");
|
||||||
|
logger.setOptions({
|
||||||
|
"level": levels[level]
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
levels: levels,
|
||||||
|
logger: logger,
|
||||||
|
set_log_level: set_log_level
|
||||||
|
};
|
|
@ -0,0 +1,735 @@
|
||||||
|
var Anchor, Angle, AngleSpec, AngleUnits, Any, Array, Backbone, Bool, Color, ColorSpec, Dimension, Direction, DirectionSpec, Distance, DistanceSpec, Distribution, Font, FontSizeSpec, FontStyle, Instance, LegendLocation, LineCap, LineJoin, Location, Number, NumberSpec, Orientation, Property, RenderLevel, RenderMode, SizingMode, SpatialUnits, String, StringSpec, TextAlign, TextBaseline, TransformStepMode, _, enum_prop, enums, simple_prop, svg_colors, units_prop, valid_rgb,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty,
|
||||||
|
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
enums = require("./enums");
|
||||||
|
|
||||||
|
svg_colors = require("./util/svg_colors");
|
||||||
|
|
||||||
|
valid_rgb = require("./util/color").valid_rgb;
|
||||||
|
|
||||||
|
Property = (function(superClass) {
|
||||||
|
extend(Property, superClass);
|
||||||
|
|
||||||
|
function Property() {
|
||||||
|
return Property.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Property.prototype.dataspec = false;
|
||||||
|
|
||||||
|
Property.prototype.specifiers = ['field', 'value'];
|
||||||
|
|
||||||
|
Property.prototype.initialize = function(attrs, options) {
|
||||||
|
var attr, obj;
|
||||||
|
Property.__super__.initialize.call(this, attrs, options);
|
||||||
|
this._init(false);
|
||||||
|
obj = this.get('obj');
|
||||||
|
attr = this.get('attr');
|
||||||
|
this.listenTo(obj, "change:" + attr, function() {
|
||||||
|
this._init();
|
||||||
|
return obj.trigger("propchange");
|
||||||
|
});
|
||||||
|
this.listenTo(this, "change:obj", function() {
|
||||||
|
throw new Error("attempted to reset 'obj' on Property");
|
||||||
|
});
|
||||||
|
return this.listenTo(this, "change:attr", function() {
|
||||||
|
throw new Error("attempted to reset 'attr' on Property");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Property.prototype.update = function() {
|
||||||
|
return this._init();
|
||||||
|
};
|
||||||
|
|
||||||
|
Property.prototype.init = function() {};
|
||||||
|
|
||||||
|
Property.prototype.transform = function(values) {
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
Property.prototype.validate = function(value) {};
|
||||||
|
|
||||||
|
Property.prototype.value = function(do_spec_transform) {
|
||||||
|
var ret;
|
||||||
|
if (do_spec_transform == null) {
|
||||||
|
do_spec_transform = true;
|
||||||
|
}
|
||||||
|
if (_.isUndefined(this.spec.value)) {
|
||||||
|
throw new Error("attempted to retrieve property value for property without value specification");
|
||||||
|
}
|
||||||
|
ret = this.transform([this.spec.value])[0];
|
||||||
|
if ((this.spec.transform != null) && do_spec_transform) {
|
||||||
|
ret = this.spec.transform.compute(ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
Property.prototype.array = function(source) {
|
||||||
|
var data, i, length, ret, value;
|
||||||
|
if (!this.dataspec) {
|
||||||
|
throw new Error("attempted to retrieve property array for non-dataspec property");
|
||||||
|
}
|
||||||
|
data = source.get('data');
|
||||||
|
if (this.spec.field != null) {
|
||||||
|
if (this.spec.field in data) {
|
||||||
|
ret = this.transform(source.get_column(this.spec.field));
|
||||||
|
} else {
|
||||||
|
throw new Error("attempted to retrieve property array for nonexistent field '" + this.spec.field + "'");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
length = source.get_length();
|
||||||
|
if (length == null) {
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
|
value = this.value(false);
|
||||||
|
ret = (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(value);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
if (this.spec.transform != null) {
|
||||||
|
ret = this.spec.transform.v_compute(ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
Property.prototype._init = function(trigger) {
|
||||||
|
var attr, attr_value, default_value, obj;
|
||||||
|
if (trigger == null) {
|
||||||
|
trigger = true;
|
||||||
|
}
|
||||||
|
obj = this.get('obj');
|
||||||
|
if (obj == null) {
|
||||||
|
throw new Error("missing property object");
|
||||||
|
}
|
||||||
|
if (obj.properties == null) {
|
||||||
|
throw new Error("property object must be a HasProps");
|
||||||
|
}
|
||||||
|
attr = this.get('attr');
|
||||||
|
if (attr == null) {
|
||||||
|
throw new Error("missing property attr");
|
||||||
|
}
|
||||||
|
attr_value = obj.get(attr);
|
||||||
|
if (_.isUndefined(attr_value)) {
|
||||||
|
default_value = this.get('default_value');
|
||||||
|
attr_value = (function() {
|
||||||
|
switch (false) {
|
||||||
|
case !_.isUndefined(default_value):
|
||||||
|
return null;
|
||||||
|
case !_.isArray(default_value):
|
||||||
|
return _.clone(default_value);
|
||||||
|
case !_.isFunction(default_value):
|
||||||
|
return default_value(obj);
|
||||||
|
default:
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
obj.set(attr, attr_value, {
|
||||||
|
silent: true,
|
||||||
|
defaults: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (_.isArray(attr_value)) {
|
||||||
|
this.spec = {
|
||||||
|
value: attr_value
|
||||||
|
};
|
||||||
|
} else if (_.isObject(attr_value) && _.size(_.pick.apply(null, [attr_value].concat(this.specifiers))) === 1) {
|
||||||
|
this.spec = attr_value;
|
||||||
|
} else {
|
||||||
|
this.spec = {
|
||||||
|
value: attr_value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if ((this.spec.field != null) && !_.isString(this.spec.field)) {
|
||||||
|
throw new Error("field value for property '" + attr + "' is not a string");
|
||||||
|
}
|
||||||
|
if (this.spec.value != null) {
|
||||||
|
this.validate(this.spec.value);
|
||||||
|
}
|
||||||
|
this.init();
|
||||||
|
if (trigger) {
|
||||||
|
return this.trigger("change");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Property;
|
||||||
|
|
||||||
|
})(Backbone.Model);
|
||||||
|
|
||||||
|
simple_prop = function(name, pred) {
|
||||||
|
var Prop;
|
||||||
|
return Prop = (function(superClass) {
|
||||||
|
extend(Prop, superClass);
|
||||||
|
|
||||||
|
function Prop() {
|
||||||
|
return Prop.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Prop.prototype.toString = function() {
|
||||||
|
return name + "(obj: " + (this.get(obj).id) + ", spec: " + (JSON.stringify(this.spec)) + ")";
|
||||||
|
};
|
||||||
|
|
||||||
|
Prop.prototype.validate = function(value) {
|
||||||
|
var attr;
|
||||||
|
if (!pred(value)) {
|
||||||
|
attr = this.get('attr');
|
||||||
|
throw new Error(name + " property '" + attr + "' given invalid value: " + value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Prop;
|
||||||
|
|
||||||
|
})(Property);
|
||||||
|
};
|
||||||
|
|
||||||
|
Any = (function(superClass) {
|
||||||
|
extend(Any, superClass);
|
||||||
|
|
||||||
|
function Any() {
|
||||||
|
return Any.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Any;
|
||||||
|
|
||||||
|
})(simple_prop("Any", function(x) {
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Array = (function(superClass) {
|
||||||
|
extend(Array, superClass);
|
||||||
|
|
||||||
|
function Array() {
|
||||||
|
return Array.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array;
|
||||||
|
|
||||||
|
})(simple_prop("Array", function(x) {
|
||||||
|
return _.isArray(x) || x instanceof Float64Array;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Bool = (function(superClass) {
|
||||||
|
extend(Bool, superClass);
|
||||||
|
|
||||||
|
function Bool() {
|
||||||
|
return Bool.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bool;
|
||||||
|
|
||||||
|
})(simple_prop("Bool", _.isBoolean));
|
||||||
|
|
||||||
|
Color = (function(superClass) {
|
||||||
|
extend(Color, superClass);
|
||||||
|
|
||||||
|
function Color() {
|
||||||
|
return Color.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color;
|
||||||
|
|
||||||
|
})(simple_prop("Color", function(x) {
|
||||||
|
return (svg_colors[x.toLowerCase()] != null) || x.substring(0, 1) === "#" || valid_rgb(x);
|
||||||
|
}));
|
||||||
|
|
||||||
|
Instance = (function(superClass) {
|
||||||
|
extend(Instance, superClass);
|
||||||
|
|
||||||
|
function Instance() {
|
||||||
|
return Instance.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Instance;
|
||||||
|
|
||||||
|
})(simple_prop("Instance", function(x) {
|
||||||
|
return x.properties != null;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Number = (function(superClass) {
|
||||||
|
extend(Number, superClass);
|
||||||
|
|
||||||
|
function Number() {
|
||||||
|
return Number.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number;
|
||||||
|
|
||||||
|
})(simple_prop("Number", function(x) {
|
||||||
|
return _.isNumber(x) || _.isBoolean(x);
|
||||||
|
}));
|
||||||
|
|
||||||
|
String = (function(superClass) {
|
||||||
|
extend(String, superClass);
|
||||||
|
|
||||||
|
function String() {
|
||||||
|
return String.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String;
|
||||||
|
|
||||||
|
})(simple_prop("String", _.isString));
|
||||||
|
|
||||||
|
Font = (function(superClass) {
|
||||||
|
extend(Font, superClass);
|
||||||
|
|
||||||
|
function Font() {
|
||||||
|
return Font.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Font;
|
||||||
|
|
||||||
|
})(String);
|
||||||
|
|
||||||
|
enum_prop = function(name, enum_values) {
|
||||||
|
var Enum;
|
||||||
|
return Enum = (function(superClass) {
|
||||||
|
extend(Enum, superClass);
|
||||||
|
|
||||||
|
function Enum() {
|
||||||
|
return Enum.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum.prototype.toString = function() {
|
||||||
|
return name + "(obj: " + (this.get(obj).id) + ", spec: " + (JSON.stringify(this.spec)) + ")";
|
||||||
|
};
|
||||||
|
|
||||||
|
return Enum;
|
||||||
|
|
||||||
|
})(simple_prop(name, function(x) {
|
||||||
|
return indexOf.call(enum_values, x) >= 0;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
Anchor = (function(superClass) {
|
||||||
|
extend(Anchor, superClass);
|
||||||
|
|
||||||
|
function Anchor() {
|
||||||
|
return Anchor.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Anchor;
|
||||||
|
|
||||||
|
})(enum_prop("Anchor", enums.LegendLocation));
|
||||||
|
|
||||||
|
AngleUnits = (function(superClass) {
|
||||||
|
extend(AngleUnits, superClass);
|
||||||
|
|
||||||
|
function AngleUnits() {
|
||||||
|
return AngleUnits.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AngleUnits;
|
||||||
|
|
||||||
|
})(enum_prop("AngleUnits", enums.AngleUnits));
|
||||||
|
|
||||||
|
Direction = (function(superClass) {
|
||||||
|
extend(Direction, superClass);
|
||||||
|
|
||||||
|
function Direction() {
|
||||||
|
return Direction.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction.prototype.transform = function(values) {
|
||||||
|
var i, j, ref, result;
|
||||||
|
result = new Uint8Array(values.length);
|
||||||
|
for (i = j = 0, ref = values.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
switch (values[i]) {
|
||||||
|
case 'clock':
|
||||||
|
result[i] = false;
|
||||||
|
break;
|
||||||
|
case 'anticlock':
|
||||||
|
result[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Direction;
|
||||||
|
|
||||||
|
})(enum_prop("Direction", enums.Direction));
|
||||||
|
|
||||||
|
Dimension = (function(superClass) {
|
||||||
|
extend(Dimension, superClass);
|
||||||
|
|
||||||
|
function Dimension() {
|
||||||
|
return Dimension.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dimension;
|
||||||
|
|
||||||
|
})(enum_prop("Dimension", enums.Dimension));
|
||||||
|
|
||||||
|
FontStyle = (function(superClass) {
|
||||||
|
extend(FontStyle, superClass);
|
||||||
|
|
||||||
|
function FontStyle() {
|
||||||
|
return FontStyle.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FontStyle;
|
||||||
|
|
||||||
|
})(enum_prop("FontStyle", enums.FontStyle));
|
||||||
|
|
||||||
|
LineCap = (function(superClass) {
|
||||||
|
extend(LineCap, superClass);
|
||||||
|
|
||||||
|
function LineCap() {
|
||||||
|
return LineCap.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LineCap;
|
||||||
|
|
||||||
|
})(enum_prop("LineCap", enums.LineCap));
|
||||||
|
|
||||||
|
LineJoin = (function(superClass) {
|
||||||
|
extend(LineJoin, superClass);
|
||||||
|
|
||||||
|
function LineJoin() {
|
||||||
|
return LineJoin.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LineJoin;
|
||||||
|
|
||||||
|
})(enum_prop("LineJoin", enums.LineJoin));
|
||||||
|
|
||||||
|
LegendLocation = (function(superClass) {
|
||||||
|
extend(LegendLocation, superClass);
|
||||||
|
|
||||||
|
function LegendLocation() {
|
||||||
|
return LegendLocation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LegendLocation;
|
||||||
|
|
||||||
|
})(enum_prop("LegendLocation", enums.LegendLocation));
|
||||||
|
|
||||||
|
Location = (function(superClass) {
|
||||||
|
extend(Location, superClass);
|
||||||
|
|
||||||
|
function Location() {
|
||||||
|
return Location.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Location;
|
||||||
|
|
||||||
|
})(enum_prop("Location", enums.Location));
|
||||||
|
|
||||||
|
Orientation = (function(superClass) {
|
||||||
|
extend(Orientation, superClass);
|
||||||
|
|
||||||
|
function Orientation() {
|
||||||
|
return Orientation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Orientation;
|
||||||
|
|
||||||
|
})(enum_prop("Orientation", enums.Orientation));
|
||||||
|
|
||||||
|
TextAlign = (function(superClass) {
|
||||||
|
extend(TextAlign, superClass);
|
||||||
|
|
||||||
|
function TextAlign() {
|
||||||
|
return TextAlign.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextAlign;
|
||||||
|
|
||||||
|
})(enum_prop("TextAlign", enums.TextAlign));
|
||||||
|
|
||||||
|
TextBaseline = (function(superClass) {
|
||||||
|
extend(TextBaseline, superClass);
|
||||||
|
|
||||||
|
function TextBaseline() {
|
||||||
|
return TextBaseline.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextBaseline;
|
||||||
|
|
||||||
|
})(enum_prop("TextBaseline", enums.TextBaseline));
|
||||||
|
|
||||||
|
RenderLevel = (function(superClass) {
|
||||||
|
extend(RenderLevel, superClass);
|
||||||
|
|
||||||
|
function RenderLevel() {
|
||||||
|
return RenderLevel.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RenderLevel;
|
||||||
|
|
||||||
|
})(enum_prop("RenderLevel", enums.RenderLevel));
|
||||||
|
|
||||||
|
RenderMode = (function(superClass) {
|
||||||
|
extend(RenderMode, superClass);
|
||||||
|
|
||||||
|
function RenderMode() {
|
||||||
|
return RenderMode.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RenderMode;
|
||||||
|
|
||||||
|
})(enum_prop("RenderMode", enums.RenderMode));
|
||||||
|
|
||||||
|
SizingMode = (function(superClass) {
|
||||||
|
extend(SizingMode, superClass);
|
||||||
|
|
||||||
|
function SizingMode() {
|
||||||
|
return SizingMode.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SizingMode;
|
||||||
|
|
||||||
|
})(enum_prop("SizingMode", enums.SizingMode));
|
||||||
|
|
||||||
|
SpatialUnits = (function(superClass) {
|
||||||
|
extend(SpatialUnits, superClass);
|
||||||
|
|
||||||
|
function SpatialUnits() {
|
||||||
|
return SpatialUnits.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpatialUnits;
|
||||||
|
|
||||||
|
})(enum_prop("SpatialUnits", enums.SpatialUnits));
|
||||||
|
|
||||||
|
Distribution = (function(superClass) {
|
||||||
|
extend(Distribution, superClass);
|
||||||
|
|
||||||
|
function Distribution() {
|
||||||
|
return Distribution.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Distribution;
|
||||||
|
|
||||||
|
})(enum_prop("Distribution", enums.DistributionTypes));
|
||||||
|
|
||||||
|
TransformStepMode = (function(superClass) {
|
||||||
|
extend(TransformStepMode, superClass);
|
||||||
|
|
||||||
|
function TransformStepMode() {
|
||||||
|
return TransformStepMode.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransformStepMode;
|
||||||
|
|
||||||
|
})(enum_prop("TransformStepMode", enums.TransformStepModes));
|
||||||
|
|
||||||
|
units_prop = function(name, valid_units, default_units) {
|
||||||
|
var UnitsProp;
|
||||||
|
return UnitsProp = (function(superClass) {
|
||||||
|
extend(UnitsProp, superClass);
|
||||||
|
|
||||||
|
function UnitsProp() {
|
||||||
|
return UnitsProp.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitsProp.prototype.toString = function() {
|
||||||
|
return name + "(obj: " + (this.get(obj).id) + ", spec: " + (JSON.stringify(this.spec)) + ")";
|
||||||
|
};
|
||||||
|
|
||||||
|
UnitsProp.prototype.init = function() {
|
||||||
|
var units;
|
||||||
|
if (this.spec.units == null) {
|
||||||
|
this.spec.units = default_units;
|
||||||
|
}
|
||||||
|
this.units = this.spec.units;
|
||||||
|
units = this.spec.units;
|
||||||
|
if (indexOf.call(valid_units, units) < 0) {
|
||||||
|
throw new Error(name + " units must be one of " + valid_units + ", given invalid value: " + units);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return UnitsProp;
|
||||||
|
|
||||||
|
})(Number);
|
||||||
|
};
|
||||||
|
|
||||||
|
Angle = (function(superClass) {
|
||||||
|
extend(Angle, superClass);
|
||||||
|
|
||||||
|
function Angle() {
|
||||||
|
return Angle.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Angle.prototype.transform = function(values) {
|
||||||
|
var x;
|
||||||
|
if (this.spec.units === "deg") {
|
||||||
|
values = (function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = values.length; j < len; j++) {
|
||||||
|
x = values[j];
|
||||||
|
results.push(x * Math.PI / 180.0);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
values = (function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = values.length; j < len; j++) {
|
||||||
|
x = values[j];
|
||||||
|
results.push(-x);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
return Angle.__super__.transform.call(this, values);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Angle;
|
||||||
|
|
||||||
|
})(units_prop("Angle", enums.AngleUnits, "rad"));
|
||||||
|
|
||||||
|
Distance = (function(superClass) {
|
||||||
|
extend(Distance, superClass);
|
||||||
|
|
||||||
|
function Distance() {
|
||||||
|
return Distance.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Distance;
|
||||||
|
|
||||||
|
})(units_prop("Distance", enums.SpatialUnits, "data"));
|
||||||
|
|
||||||
|
AngleSpec = (function(superClass) {
|
||||||
|
extend(AngleSpec, superClass);
|
||||||
|
|
||||||
|
function AngleSpec() {
|
||||||
|
return AngleSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AngleSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return AngleSpec;
|
||||||
|
|
||||||
|
})(Angle);
|
||||||
|
|
||||||
|
ColorSpec = (function(superClass) {
|
||||||
|
extend(ColorSpec, superClass);
|
||||||
|
|
||||||
|
function ColorSpec() {
|
||||||
|
return ColorSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return ColorSpec;
|
||||||
|
|
||||||
|
})(Color);
|
||||||
|
|
||||||
|
DirectionSpec = (function(superClass) {
|
||||||
|
extend(DirectionSpec, superClass);
|
||||||
|
|
||||||
|
function DirectionSpec() {
|
||||||
|
return DirectionSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectionSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return DirectionSpec;
|
||||||
|
|
||||||
|
})(Distance);
|
||||||
|
|
||||||
|
DistanceSpec = (function(superClass) {
|
||||||
|
extend(DistanceSpec, superClass);
|
||||||
|
|
||||||
|
function DistanceSpec() {
|
||||||
|
return DistanceSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
DistanceSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return DistanceSpec;
|
||||||
|
|
||||||
|
})(Distance);
|
||||||
|
|
||||||
|
FontSizeSpec = (function(superClass) {
|
||||||
|
extend(FontSizeSpec, superClass);
|
||||||
|
|
||||||
|
function FontSizeSpec() {
|
||||||
|
return FontSizeSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontSizeSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return FontSizeSpec;
|
||||||
|
|
||||||
|
})(String);
|
||||||
|
|
||||||
|
NumberSpec = (function(superClass) {
|
||||||
|
extend(NumberSpec, superClass);
|
||||||
|
|
||||||
|
function NumberSpec() {
|
||||||
|
return NumberSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return NumberSpec;
|
||||||
|
|
||||||
|
})(Number);
|
||||||
|
|
||||||
|
StringSpec = (function(superClass) {
|
||||||
|
extend(StringSpec, superClass);
|
||||||
|
|
||||||
|
function StringSpec() {
|
||||||
|
return StringSpec.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSpec.prototype.dataspec = true;
|
||||||
|
|
||||||
|
return StringSpec;
|
||||||
|
|
||||||
|
})(String);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Property: Property,
|
||||||
|
simple_prop: simple_prop,
|
||||||
|
enum_prop: enum_prop,
|
||||||
|
units_prop: units_prop,
|
||||||
|
Anchor: Anchor,
|
||||||
|
Any: Any,
|
||||||
|
Angle: Angle,
|
||||||
|
AngleUnits: AngleUnits,
|
||||||
|
Array: Array,
|
||||||
|
Bool: Bool,
|
||||||
|
Boolean: Bool,
|
||||||
|
Color: Color,
|
||||||
|
Dimension: Dimension,
|
||||||
|
Direction: Direction,
|
||||||
|
Distance: Distance,
|
||||||
|
Font: Font,
|
||||||
|
FontStyle: FontStyle,
|
||||||
|
Instance: Instance,
|
||||||
|
LegendLocation: LegendLocation,
|
||||||
|
LineCap: LineCap,
|
||||||
|
LineJoin: LineJoin,
|
||||||
|
Location: Location,
|
||||||
|
Number: Number,
|
||||||
|
Int: Number,
|
||||||
|
Orientation: Orientation,
|
||||||
|
RenderLevel: RenderLevel,
|
||||||
|
RenderMode: RenderMode,
|
||||||
|
SizingMode: SizingMode,
|
||||||
|
SpatialUnits: SpatialUnits,
|
||||||
|
String: String,
|
||||||
|
TextAlign: TextAlign,
|
||||||
|
TextBaseline: TextBaseline,
|
||||||
|
Distribution: Distribution,
|
||||||
|
TransformStepMode: TransformStepMode,
|
||||||
|
AngleSpec: AngleSpec,
|
||||||
|
ColorSpec: ColorSpec,
|
||||||
|
DirectionSpec: DirectionSpec,
|
||||||
|
DistanceSpec: DistanceSpec,
|
||||||
|
FontSizeSpec: FontSizeSpec,
|
||||||
|
NumberSpec: NumberSpec,
|
||||||
|
StringSpec: StringSpec
|
||||||
|
};
|
|
@ -0,0 +1,76 @@
|
||||||
|
var _, _fill_mixin, _gen_mixin, _line_mixin, _text_mixin, create, fill, line, p, text;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
p = require("./properties");
|
||||||
|
|
||||||
|
_gen_mixin = function(mixin, prefix) {
|
||||||
|
var name, result, type;
|
||||||
|
result = {};
|
||||||
|
if (prefix == null) {
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
for (name in mixin) {
|
||||||
|
type = mixin[name];
|
||||||
|
result[prefix + name] = type;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
_line_mixin = {
|
||||||
|
line_color: [p.ColorSpec, 'black'],
|
||||||
|
line_width: [p.NumberSpec, 1],
|
||||||
|
line_alpha: [p.NumberSpec, 1.0],
|
||||||
|
line_join: [p.LineJoin, 'miter'],
|
||||||
|
line_cap: [p.LineCap, 'butt'],
|
||||||
|
line_dash: [p.Array, []],
|
||||||
|
line_dash_offset: [p.Number, 0]
|
||||||
|
};
|
||||||
|
|
||||||
|
line = function(prefix) {
|
||||||
|
return _gen_mixin(_line_mixin, prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
_fill_mixin = {
|
||||||
|
fill_color: [p.ColorSpec, 'gray'],
|
||||||
|
fill_alpha: [p.NumberSpec, 1.0]
|
||||||
|
};
|
||||||
|
|
||||||
|
fill = function(prefix) {
|
||||||
|
return _gen_mixin(_fill_mixin, prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
_text_mixin = {
|
||||||
|
text_font: [p.Font, 'helvetica'],
|
||||||
|
text_font_size: [p.FontSizeSpec, '12pt'],
|
||||||
|
text_font_style: [p.FontStyle, 'normal'],
|
||||||
|
text_color: [p.ColorSpec, '#444444'],
|
||||||
|
text_alpha: [p.NumberSpec, 1.0],
|
||||||
|
text_align: [p.TextAlign, 'left'],
|
||||||
|
text_baseline: [p.TextBaseline, 'bottom']
|
||||||
|
};
|
||||||
|
|
||||||
|
text = function(prefix) {
|
||||||
|
return _gen_mixin(_text_mixin, prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
create = function(configs) {
|
||||||
|
var config, i, kind, len, prefix, ref, result;
|
||||||
|
result = {};
|
||||||
|
for (i = 0, len = configs.length; i < len; i++) {
|
||||||
|
config = configs[i];
|
||||||
|
ref = config.split(":"), kind = ref[0], prefix = ref[1];
|
||||||
|
if (this[kind] == null) {
|
||||||
|
throw Error("Unknown property mixin kind '" + kind + "'");
|
||||||
|
}
|
||||||
|
result = _.extend(result, this[kind](prefix));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
line: line,
|
||||||
|
fill: fill,
|
||||||
|
text: text,
|
||||||
|
create: create
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
var empty, union;
|
||||||
|
|
||||||
|
empty = function() {
|
||||||
|
return {
|
||||||
|
minX: Infinity,
|
||||||
|
minY: Infinity,
|
||||||
|
maxX: -Infinity,
|
||||||
|
maxY: -Infinity
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union = function(a, b) {
|
||||||
|
var r;
|
||||||
|
r = {};
|
||||||
|
r.minX = Math.min(a.minX, b.minX);
|
||||||
|
r.maxX = Math.max(a.maxX, b.maxX);
|
||||||
|
r.minY = Math.min(a.minY, b.minY);
|
||||||
|
r.maxY = Math.max(a.maxY, b.maxY);
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
empty: empty,
|
||||||
|
union: union
|
||||||
|
};
|
|
@ -0,0 +1,100 @@
|
||||||
|
var fixup_ellipse, fixup_image_smoothing, fixup_line_dash, fixup_line_dash_offset, fixup_measure_text, get_scale_ratio;
|
||||||
|
|
||||||
|
fixup_line_dash = function(ctx) {
|
||||||
|
if (!ctx.setLineDash) {
|
||||||
|
ctx.setLineDash = function(dash) {
|
||||||
|
ctx.mozDash = dash;
|
||||||
|
return ctx.webkitLineDash = dash;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!ctx.getLineDash) {
|
||||||
|
return ctx.getLineDash = function() {
|
||||||
|
return ctx.mozDash;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixup_line_dash_offset = function(ctx) {
|
||||||
|
ctx.setLineDashOffset = function(dash_offset) {
|
||||||
|
ctx.lineDashOffset = dash_offset;
|
||||||
|
ctx.mozDashOffset = dash_offset;
|
||||||
|
return ctx.webkitLineDashOffset = dash_offset;
|
||||||
|
};
|
||||||
|
return ctx.getLineDashOffset = function() {
|
||||||
|
return ctx.mozDashOffset;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fixup_image_smoothing = function(ctx) {
|
||||||
|
ctx.setImageSmoothingEnabled = function(value) {
|
||||||
|
ctx.imageSmoothingEnabled = value;
|
||||||
|
ctx.mozImageSmoothingEnabled = value;
|
||||||
|
ctx.oImageSmoothingEnabled = value;
|
||||||
|
return ctx.webkitImageSmoothingEnabled = value;
|
||||||
|
};
|
||||||
|
return ctx.getImageSmoothingEnabled = function() {
|
||||||
|
var ref;
|
||||||
|
return (ref = ctx.imageSmoothingEnabled) != null ? ref : true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fixup_measure_text = function(ctx) {
|
||||||
|
if (ctx.measureText && (ctx.html5MeasureText == null)) {
|
||||||
|
ctx.html5MeasureText = ctx.measureText;
|
||||||
|
return ctx.measureText = function(text) {
|
||||||
|
var textMetrics;
|
||||||
|
textMetrics = ctx.html5MeasureText(text);
|
||||||
|
textMetrics.ascent = ctx.html5MeasureText("m").width * 1.6;
|
||||||
|
return textMetrics;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
get_scale_ratio = function(ctx, hidpi) {
|
||||||
|
var backingStoreRatio, devicePixelRatio;
|
||||||
|
if (hidpi) {
|
||||||
|
devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
|
||||||
|
return devicePixelRatio / backingStoreRatio;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixup_ellipse = function(ctx) {
|
||||||
|
var ellipse_bezier;
|
||||||
|
ellipse_bezier = function(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) {
|
||||||
|
var c, rx, ry;
|
||||||
|
if (anticlockwise == null) {
|
||||||
|
anticlockwise = false;
|
||||||
|
}
|
||||||
|
c = 0.551784;
|
||||||
|
ctx.translate(x, y);
|
||||||
|
ctx.rotate(rotation);
|
||||||
|
rx = radiusX;
|
||||||
|
ry = radiusY;
|
||||||
|
if (anticlockwise) {
|
||||||
|
rx = -radiusX;
|
||||||
|
ry = -radiusY;
|
||||||
|
}
|
||||||
|
ctx.moveTo(-rx, 0);
|
||||||
|
ctx.bezierCurveTo(-rx, ry * c, -rx * c, ry, 0, ry);
|
||||||
|
ctx.bezierCurveTo(rx * c, ry, rx, ry * c, rx, 0);
|
||||||
|
ctx.bezierCurveTo(rx, -ry * c, rx * c, -ry, 0, -ry);
|
||||||
|
ctx.bezierCurveTo(-rx * c, -ry, -rx, -ry * c, -rx, 0);
|
||||||
|
ctx.rotate(-rotation);
|
||||||
|
ctx.translate(-x, -y);
|
||||||
|
};
|
||||||
|
if (!ctx.ellipse) {
|
||||||
|
return ctx.ellipse = ellipse_bezier;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fixup_image_smoothing: fixup_image_smoothing,
|
||||||
|
fixup_line_dash: fixup_line_dash,
|
||||||
|
fixup_line_dash_offset: fixup_line_dash_offset,
|
||||||
|
fixup_measure_text: fixup_measure_text,
|
||||||
|
get_scale_ratio: get_scale_ratio,
|
||||||
|
fixup_ellipse: fixup_ellipse
|
||||||
|
};
|
|
@ -0,0 +1,117 @@
|
||||||
|
var _component2hex, color2hex, color2rgba, svg_colors, valid_rgb,
|
||||||
|
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
|
svg_colors = require("./svg_colors");
|
||||||
|
|
||||||
|
_component2hex = function(v) {
|
||||||
|
var h;
|
||||||
|
h = Number(v).toString(16);
|
||||||
|
return h = h.length === 1 ? '0' + h : h;
|
||||||
|
};
|
||||||
|
|
||||||
|
color2hex = function(color) {
|
||||||
|
var hex, rgb, v;
|
||||||
|
color = color + '';
|
||||||
|
if (color.indexOf('#') === 0) {
|
||||||
|
return color;
|
||||||
|
} else if (svg_colors[color] != null) {
|
||||||
|
return svg_colors[color];
|
||||||
|
} else if (color.indexOf('rgb') === 0) {
|
||||||
|
rgb = color.match(/\d+/g);
|
||||||
|
hex = ((function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = rgb.length; j < len; j++) {
|
||||||
|
v = rgb[j];
|
||||||
|
results.push(_component2hex(v));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})()).join('');
|
||||||
|
return '#' + hex.slice(0, 8);
|
||||||
|
} else {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
color2rgba = function(color, alpha) {
|
||||||
|
var hex, i, rgba;
|
||||||
|
if (alpha == null) {
|
||||||
|
alpha = 1;
|
||||||
|
}
|
||||||
|
if (!color) {
|
||||||
|
return [0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
hex = color2hex(color);
|
||||||
|
hex = hex.replace(/ |#/g, '');
|
||||||
|
if (hex.length <= 4) {
|
||||||
|
hex = hex.replace(/(.)/g, '$1$1');
|
||||||
|
}
|
||||||
|
hex = hex.match(/../g);
|
||||||
|
rgba = (function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = hex.length; j < len; j++) {
|
||||||
|
i = hex[j];
|
||||||
|
results.push(parseInt(i, 16) / 255);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
while (rgba.length < 3) {
|
||||||
|
rgba.push(0);
|
||||||
|
}
|
||||||
|
if (rgba.length < 4) {
|
||||||
|
rgba.push(alpha);
|
||||||
|
}
|
||||||
|
return rgba.slice(0, 4);
|
||||||
|
};
|
||||||
|
|
||||||
|
valid_rgb = function(value) {
|
||||||
|
var contents, params, ref, rgb;
|
||||||
|
switch (value.substring(0, 4)) {
|
||||||
|
case "rgba":
|
||||||
|
params = {
|
||||||
|
start: "rgba(",
|
||||||
|
len: 4,
|
||||||
|
alpha: true
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case "rgb(":
|
||||||
|
params = {
|
||||||
|
start: "rgb(",
|
||||||
|
len: 3,
|
||||||
|
alpha: false
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (new RegExp(".*?(\\.).*(,)").test(value)) {
|
||||||
|
throw new Error("color expects integers for rgb in rgb/rgba tuple, received " + value);
|
||||||
|
}
|
||||||
|
contents = value.replace(params.start, "").replace(")", "").split(',').map(parseFloat);
|
||||||
|
if (contents.length !== params.len) {
|
||||||
|
throw new Error("color expects rgba " + expect_len + "-tuple, received " + value);
|
||||||
|
}
|
||||||
|
if (params.alpha && !((0 <= (ref = contents[3]) && ref <= 1))) {
|
||||||
|
throw new Error("color expects rgba 4-tuple to have alpha value between 0 and 1");
|
||||||
|
}
|
||||||
|
if (indexOf.call((function() {
|
||||||
|
var j, len, ref1, results;
|
||||||
|
ref1 = contents.slice(0, 3);
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref1.length; j < len; j++) {
|
||||||
|
rgb = ref1[j];
|
||||||
|
results.push((0 <= rgb && rgb <= 255));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})(), false) >= 0) {
|
||||||
|
throw new Error("color expects rgb to have value between 0 and 255");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
color2hex: color2hex,
|
||||||
|
color2rgba: color2rgba,
|
||||||
|
valid_rgb: valid_rgb
|
||||||
|
};
|
|
@ -0,0 +1,177 @@
|
||||||
|
var MultiDict, Set, _;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
MultiDict = (function() {
|
||||||
|
function MultiDict() {
|
||||||
|
this._dict = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiDict.prototype._existing = function(key) {
|
||||||
|
if (key in this._dict) {
|
||||||
|
return this._dict[key];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiDict.prototype.add_value = function(key, value) {
|
||||||
|
var existing;
|
||||||
|
if (value === null) {
|
||||||
|
throw new Error("Can't put null in this dict");
|
||||||
|
}
|
||||||
|
if (_.isArray(value)) {
|
||||||
|
throw new Error("Can't put arrays in this dict");
|
||||||
|
}
|
||||||
|
existing = this._existing(key);
|
||||||
|
if (existing === null) {
|
||||||
|
return this._dict[key] = value;
|
||||||
|
} else if (_.isArray(existing)) {
|
||||||
|
return existing.push(value);
|
||||||
|
} else {
|
||||||
|
return this._dict[key] = [existing, value];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiDict.prototype.remove_value = function(key, value) {
|
||||||
|
var existing, new_array;
|
||||||
|
existing = this._existing(key);
|
||||||
|
if (_.isArray(existing)) {
|
||||||
|
new_array = _.without(existing, value);
|
||||||
|
if (new_array.length > 0) {
|
||||||
|
return this._dict[key] = new_array;
|
||||||
|
} else {
|
||||||
|
return delete this._dict[key];
|
||||||
|
}
|
||||||
|
} else if (_.isEqual(existing, value)) {
|
||||||
|
return delete this._dict[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiDict.prototype.get_one = function(key, duplicate_error) {
|
||||||
|
var existing;
|
||||||
|
existing = this._existing(key);
|
||||||
|
if (_.isArray(existing)) {
|
||||||
|
if (existing.length === 1) {
|
||||||
|
return existing[0];
|
||||||
|
} else {
|
||||||
|
throw new Error(duplicate_error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return MultiDict;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
Set = (function() {
|
||||||
|
function Set(array) {
|
||||||
|
if (!array) {
|
||||||
|
this.values = [];
|
||||||
|
} else {
|
||||||
|
if (array.constructor === Set) {
|
||||||
|
return new Set(array.values);
|
||||||
|
}
|
||||||
|
if (array.constructor === Array) {
|
||||||
|
this.values = Set.compact(array);
|
||||||
|
} else {
|
||||||
|
this.values = [array];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set.compact = function(array) {
|
||||||
|
var item, j, len, newArray;
|
||||||
|
newArray = [];
|
||||||
|
for (j = 0, len = array.length; j < len; j++) {
|
||||||
|
item = array[j];
|
||||||
|
if (newArray.indexOf(item) === -1) {
|
||||||
|
newArray.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.push = function(item) {
|
||||||
|
if (this.missing(item)) {
|
||||||
|
return this.values.push(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.remove = function(item) {
|
||||||
|
var i;
|
||||||
|
i = this.values.indexOf(item);
|
||||||
|
return this.values = this.values.slice(0, i).concat(this.values.slice(i + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.length = function() {
|
||||||
|
return this.values.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.includes = function(item) {
|
||||||
|
return this.values.indexOf(item) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.missing = function(item) {
|
||||||
|
return !this.includes(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.slice = function(from, to) {
|
||||||
|
return this.values.slice(from, to);
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.join = function(str) {
|
||||||
|
return this.values.join(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.toString = function() {
|
||||||
|
return this.join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.includes = function(item) {
|
||||||
|
return this.values.indexOf(item) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.union = function(set) {
|
||||||
|
set = new Set(set);
|
||||||
|
return new Set(this.values.concat(set.values));
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.intersect = function(set) {
|
||||||
|
var item, j, len, newSet, ref;
|
||||||
|
set = new Set(set);
|
||||||
|
newSet = new Set;
|
||||||
|
ref = set.values;
|
||||||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||||||
|
item = ref[j];
|
||||||
|
if (this.includes(item) && set.includes(item)) {
|
||||||
|
newSet.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.prototype.diff = function(set) {
|
||||||
|
var item, j, len, newSet, ref;
|
||||||
|
set = new Set(set);
|
||||||
|
newSet = new Set;
|
||||||
|
ref = this.values;
|
||||||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||||||
|
item = ref[j];
|
||||||
|
if (set.missing(item)) {
|
||||||
|
newSet.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Set;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
MultiDict: MultiDict,
|
||||||
|
Set: Set
|
||||||
|
};
|
|
@ -0,0 +1,89 @@
|
||||||
|
var angle_between, angle_dist, angle_norm, array_max, array_min, atan2, random, rnorm;
|
||||||
|
|
||||||
|
array_min = function(arr) {
|
||||||
|
var len, min, val;
|
||||||
|
len = arr.length;
|
||||||
|
min = Infinity;
|
||||||
|
while (len--) {
|
||||||
|
val = arr[len];
|
||||||
|
if (val < min) {
|
||||||
|
min = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
};
|
||||||
|
|
||||||
|
array_max = function(arr) {
|
||||||
|
var len, max, val;
|
||||||
|
len = arr.length;
|
||||||
|
max = -Infinity;
|
||||||
|
while (len--) {
|
||||||
|
val = arr[len];
|
||||||
|
if (val > max) {
|
||||||
|
max = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
};
|
||||||
|
|
||||||
|
angle_norm = function(angle) {
|
||||||
|
while (angle < 0) {
|
||||||
|
angle += 2 * Math.PI;
|
||||||
|
}
|
||||||
|
while (angle > 2 * Math.PI) {
|
||||||
|
angle -= 2 * Math.PI;
|
||||||
|
}
|
||||||
|
return angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
angle_dist = function(lhs, rhs) {
|
||||||
|
return Math.abs(angle_norm(lhs - rhs));
|
||||||
|
};
|
||||||
|
|
||||||
|
angle_between = function(mid, lhs, rhs, direction) {
|
||||||
|
var d;
|
||||||
|
mid = angle_norm(mid);
|
||||||
|
d = angle_dist(lhs, rhs);
|
||||||
|
if (direction === "anticlock") {
|
||||||
|
return angle_dist(lhs, mid) <= d && angle_dist(mid, rhs) <= d;
|
||||||
|
} else {
|
||||||
|
return !(angle_dist(lhs, mid) <= d && angle_dist(mid, rhs) <= d);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
random = function() {
|
||||||
|
return Math.random();
|
||||||
|
};
|
||||||
|
|
||||||
|
atan2 = function(start, end) {
|
||||||
|
"Calculate the angle between a line containing start and end points (composed\nof [x, y] arrays) and the positive x-axis.";
|
||||||
|
return Math.atan2(end[1] - start[1], end[0] - start[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
rnorm = function(mu, sigma) {
|
||||||
|
var r1, r2, rn;
|
||||||
|
r1 = null;
|
||||||
|
r2 = null;
|
||||||
|
while (true) {
|
||||||
|
r1 = random();
|
||||||
|
r2 = random();
|
||||||
|
r2 = (2 * r2 - 1) * Math.sqrt(2 * (1 / Math.E));
|
||||||
|
if (-4 * r1 * r1 * Math.log(r1) >= r2 * r2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rn = r2 / r1;
|
||||||
|
rn = mu + sigma * rn;
|
||||||
|
return rn;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
array_min: array_min,
|
||||||
|
array_max: array_max,
|
||||||
|
angle_norm: angle_norm,
|
||||||
|
angle_dist: angle_dist,
|
||||||
|
angle_between: angle_between,
|
||||||
|
atan2: atan2,
|
||||||
|
rnorm: rnorm,
|
||||||
|
random: random
|
||||||
|
};
|
|
@ -0,0 +1,50 @@
|
||||||
|
var HasProps, _, convert_to_ref, create_ref, is_ref;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
HasProps = require("../has_props");
|
||||||
|
|
||||||
|
create_ref = function(obj) {
|
||||||
|
var ref;
|
||||||
|
if (!(obj instanceof HasProps.constructor)) {
|
||||||
|
throw new Error("can only create refs for HasProps subclasses");
|
||||||
|
}
|
||||||
|
ref = {
|
||||||
|
'type': obj.type,
|
||||||
|
'id': obj.id
|
||||||
|
};
|
||||||
|
if (obj._subtype != null) {
|
||||||
|
ref['subtype'] = obj._subtype;
|
||||||
|
}
|
||||||
|
return ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
is_ref = function(arg) {
|
||||||
|
var keys;
|
||||||
|
if (_.isObject(arg)) {
|
||||||
|
keys = _.keys(arg).sort();
|
||||||
|
if (keys.length === 2) {
|
||||||
|
return keys[0] === 'id' && keys[1] === 'type';
|
||||||
|
}
|
||||||
|
if (keys.length === 3) {
|
||||||
|
return keys[0] === 'id' && keys[1] === 'subtype' && keys[2] === 'type';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
convert_to_ref = function(value) {
|
||||||
|
if (_.isArray(value)) {
|
||||||
|
return _.map(value, convert_to_ref);
|
||||||
|
} else {
|
||||||
|
if (value instanceof HasProps.constructor) {
|
||||||
|
return value.ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
convert_to_ref: convert_to_ref,
|
||||||
|
create_ref: create_ref,
|
||||||
|
is_ref: is_ref
|
||||||
|
};
|
|
@ -0,0 +1,149 @@
|
||||||
|
module.exports = {
|
||||||
|
indianred: "#CD5C5C",
|
||||||
|
lightcoral: "#F08080",
|
||||||
|
salmon: "#FA8072",
|
||||||
|
darksalmon: "#E9967A",
|
||||||
|
lightsalmon: "#FFA07A",
|
||||||
|
crimson: "#DC143C",
|
||||||
|
red: "#FF0000",
|
||||||
|
firebrick: "#B22222",
|
||||||
|
darkred: "#8B0000",
|
||||||
|
pink: "#FFC0CB",
|
||||||
|
lightpink: "#FFB6C1",
|
||||||
|
hotpink: "#FF69B4",
|
||||||
|
deeppink: "#FF1493",
|
||||||
|
mediumvioletred: "#C71585",
|
||||||
|
palevioletred: "#DB7093",
|
||||||
|
coral: "#FF7F50",
|
||||||
|
tomato: "#FF6347",
|
||||||
|
orangered: "#FF4500",
|
||||||
|
darkorange: "#FF8C00",
|
||||||
|
orange: "#FFA500",
|
||||||
|
gold: "#FFD700",
|
||||||
|
yellow: "#FFFF00",
|
||||||
|
lightyellow: "#FFFFE0",
|
||||||
|
lemonchiffon: "#FFFACD",
|
||||||
|
lightgoldenrodyellow: "#FAFAD2",
|
||||||
|
papayawhip: "#FFEFD5",
|
||||||
|
moccasin: "#FFE4B5",
|
||||||
|
peachpuff: "#FFDAB9",
|
||||||
|
palegoldenrod: "#EEE8AA",
|
||||||
|
khaki: "#F0E68C",
|
||||||
|
darkkhaki: "#BDB76B",
|
||||||
|
lavender: "#E6E6FA",
|
||||||
|
thistle: "#D8BFD8",
|
||||||
|
plum: "#DDA0DD",
|
||||||
|
violet: "#EE82EE",
|
||||||
|
orchid: "#DA70D6",
|
||||||
|
fuchsia: "#FF00FF",
|
||||||
|
magenta: "#FF00FF",
|
||||||
|
mediumorchid: "#BA55D3",
|
||||||
|
mediumpurple: "#9370DB",
|
||||||
|
blueviolet: "#8A2BE2",
|
||||||
|
darkviolet: "#9400D3",
|
||||||
|
darkorchid: "#9932CC",
|
||||||
|
darkmagenta: "#8B008B",
|
||||||
|
purple: "#800080",
|
||||||
|
indigo: "#4B0082",
|
||||||
|
slateblue: "#6A5ACD",
|
||||||
|
darkslateblue: "#483D8B",
|
||||||
|
mediumslateblue: "#7B68EE",
|
||||||
|
greenyellow: "#ADFF2F",
|
||||||
|
chartreuse: "#7FFF00",
|
||||||
|
lawngreen: "#7CFC00",
|
||||||
|
lime: "#00FF00",
|
||||||
|
limegreen: "#32CD32",
|
||||||
|
palegreen: "#98FB98",
|
||||||
|
lightgreen: "#90EE90",
|
||||||
|
mediumspringgreen: "#00FA9A",
|
||||||
|
springgreen: "#00FF7F",
|
||||||
|
mediumseagreen: "#3CB371",
|
||||||
|
seagreen: "#2E8B57",
|
||||||
|
forestgreen: "#228B22",
|
||||||
|
green: "#008000",
|
||||||
|
darkgreen: "#006400",
|
||||||
|
yellowgreen: "#9ACD32",
|
||||||
|
olivedrab: "#6B8E23",
|
||||||
|
olive: "#808000",
|
||||||
|
darkolivegreen: "#556B2F",
|
||||||
|
mediumaquamarine: "#66CDAA",
|
||||||
|
darkseagreen: "#8FBC8F",
|
||||||
|
lightseagreen: "#20B2AA",
|
||||||
|
darkcyan: "#008B8B",
|
||||||
|
teal: "#008080",
|
||||||
|
aqua: "#00FFFF",
|
||||||
|
cyan: "#00FFFF",
|
||||||
|
lightcyan: "#E0FFFF",
|
||||||
|
paleturquoise: "#AFEEEE",
|
||||||
|
aquamarine: "#7FFFD4",
|
||||||
|
turquoise: "#40E0D0",
|
||||||
|
mediumturquoise: "#48D1CC",
|
||||||
|
darkturquoise: "#00CED1",
|
||||||
|
cadetblue: "#5F9EA0",
|
||||||
|
steelblue: "#4682B4",
|
||||||
|
lightsteelblue: "#B0C4DE",
|
||||||
|
powderblue: "#B0E0E6",
|
||||||
|
lightblue: "#ADD8E6",
|
||||||
|
skyblue: "#87CEEB",
|
||||||
|
lightskyblue: "#87CEFA",
|
||||||
|
deepskyblue: "#00BFFF",
|
||||||
|
dodgerblue: "#1E90FF",
|
||||||
|
cornflowerblue: "#6495ED",
|
||||||
|
royalblue: "#4169E1",
|
||||||
|
blue: "#0000FF",
|
||||||
|
mediumblue: "#0000CD",
|
||||||
|
darkblue: "#00008B",
|
||||||
|
navy: "#000080",
|
||||||
|
midnightblue: "#191970",
|
||||||
|
cornsilk: "#FFF8DC",
|
||||||
|
blanchedalmond: "#FFEBCD",
|
||||||
|
bisque: "#FFE4C4",
|
||||||
|
navajowhite: "#FFDEAD",
|
||||||
|
wheat: "#F5DEB3",
|
||||||
|
burlywood: "#DEB887",
|
||||||
|
tan: "#D2B48C",
|
||||||
|
rosybrown: "#BC8F8F",
|
||||||
|
sandybrown: "#F4A460",
|
||||||
|
goldenrod: "#DAA520",
|
||||||
|
darkgoldenrod: "#B8860B",
|
||||||
|
peru: "#CD853F",
|
||||||
|
chocolate: "#D2691E",
|
||||||
|
saddlebrown: "#8B4513",
|
||||||
|
sienna: "#A0522D",
|
||||||
|
brown: "#A52A2A",
|
||||||
|
maroon: "#800000",
|
||||||
|
white: "#FFFFFF",
|
||||||
|
snow: "#FFFAFA",
|
||||||
|
honeydew: "#F0FFF0",
|
||||||
|
mintcream: "#F5FFFA",
|
||||||
|
azure: "#F0FFFF",
|
||||||
|
aliceblue: "#F0F8FF",
|
||||||
|
ghostwhite: "#F8F8FF",
|
||||||
|
whitesmoke: "#F5F5F5",
|
||||||
|
seashell: "#FFF5EE",
|
||||||
|
beige: "#F5F5DC",
|
||||||
|
oldlace: "#FDF5E6",
|
||||||
|
floralwhite: "#FFFAF0",
|
||||||
|
ivory: "#FFFFF0",
|
||||||
|
antiquewhite: "#FAEBD7",
|
||||||
|
linen: "#FAF0E6",
|
||||||
|
lavenderblush: "#FFF0F5",
|
||||||
|
mistyrose: "#FFE4E1",
|
||||||
|
gainsboro: "#DCDCDC",
|
||||||
|
lightgray: "#D3D3D3",
|
||||||
|
lightgrey: "#D3D3D3",
|
||||||
|
silver: "#C0C0C0",
|
||||||
|
darkgray: "#A9A9A9",
|
||||||
|
darkgrey: "#A9A9A9",
|
||||||
|
gray: "#808080",
|
||||||
|
grey: "#808080",
|
||||||
|
dimgray: "#696969",
|
||||||
|
dimgrey: "#696969",
|
||||||
|
lightslategray: "#778899",
|
||||||
|
lightslategrey: "#778899",
|
||||||
|
slategray: "#708090",
|
||||||
|
slategrey: "#708090",
|
||||||
|
darkslategray: "#2F4F4F",
|
||||||
|
darkslategrey: "#2F4F4F",
|
||||||
|
black: "#000000"
|
||||||
|
};
|
|
@ -0,0 +1,40 @@
|
||||||
|
var $, cache, get_text_height;
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
cache = {};
|
||||||
|
|
||||||
|
get_text_height = function(font) {
|
||||||
|
var block, body, div, result, text;
|
||||||
|
if (cache[font] != null) {
|
||||||
|
return cache[font];
|
||||||
|
}
|
||||||
|
text = $('<span>Hg</span>').css({
|
||||||
|
font: font
|
||||||
|
});
|
||||||
|
block = $('<div style="display: inline-block; width: 1px; height: 0px;"> </div>');
|
||||||
|
div = $('<div></div>');
|
||||||
|
div.append(text, block);
|
||||||
|
body = $('body');
|
||||||
|
body.append(div);
|
||||||
|
try {
|
||||||
|
result = {};
|
||||||
|
block.css({
|
||||||
|
verticalAlign: 'baseline'
|
||||||
|
});
|
||||||
|
result.ascent = block.offset().top - text.offset().top;
|
||||||
|
block.css({
|
||||||
|
verticalAlign: 'bottom'
|
||||||
|
});
|
||||||
|
result.height = block.offset().top - text.offset().top;
|
||||||
|
result.descent = result.height - result.ascent;
|
||||||
|
} finally {
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
cache[font] = result;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
get_text_height: get_text_height
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
var _delay_animation, delay_animation, throttle;
|
||||||
|
|
||||||
|
_delay_animation = function(f) {
|
||||||
|
return f();
|
||||||
|
};
|
||||||
|
|
||||||
|
delay_animation = (typeof window !== "undefined" && window !== null ? window.requestAnimationFrame : void 0) || (typeof window !== "undefined" && window !== null ? window.mozRequestAnimationFrame : void 0) || (typeof window !== "undefined" && window !== null ? window.webkitRequestAnimationFrame : void 0) || (typeof window !== "undefined" && window !== null ? window.msRequestAnimationFrame : void 0) || _delay_animation;
|
||||||
|
|
||||||
|
throttle = function(func, wait) {
|
||||||
|
var args, context, later, pending, previous, ref, result, timeout;
|
||||||
|
ref = [null, null, null, null], context = ref[0], args = ref[1], timeout = ref[2], result = ref[3];
|
||||||
|
previous = 0;
|
||||||
|
pending = false;
|
||||||
|
later = function() {
|
||||||
|
previous = new Date;
|
||||||
|
timeout = null;
|
||||||
|
pending = false;
|
||||||
|
return result = func.apply(context, args);
|
||||||
|
};
|
||||||
|
return function() {
|
||||||
|
var now, remaining;
|
||||||
|
now = new Date;
|
||||||
|
remaining = wait - (now - previous);
|
||||||
|
context = this;
|
||||||
|
args = arguments;
|
||||||
|
if (remaining <= 0 && !pending) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
pending = true;
|
||||||
|
delay_animation(later);
|
||||||
|
} else if (!timeout && !pending) {
|
||||||
|
timeout = setTimeout((function() {
|
||||||
|
return delay_animation(later);
|
||||||
|
}), remaining);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
throttle: throttle
|
||||||
|
};
|
|
@ -0,0 +1,39 @@
|
||||||
|
var _, patch;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
patch = function() {
|
||||||
|
return _.uniqueId = function(prefix) {
|
||||||
|
var hexDigits, i, j, s, uuid;
|
||||||
|
s = [];
|
||||||
|
hexDigits = "0123456789ABCDEF";
|
||||||
|
for (i = j = 0; j <= 31; i = ++j) {
|
||||||
|
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||||
|
}
|
||||||
|
s[12] = "4";
|
||||||
|
s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);
|
||||||
|
uuid = s.join("");
|
||||||
|
if (prefix) {
|
||||||
|
return prefix + "-" + uuid;
|
||||||
|
} else {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
_.isNullOrUndefined = function(x) {
|
||||||
|
return _.isNull(x) || _.isUndefined(x);
|
||||||
|
};
|
||||||
|
|
||||||
|
_.setdefault = function(obj, key, value) {
|
||||||
|
if (_.has(obj, key)) {
|
||||||
|
return obj[key];
|
||||||
|
} else {
|
||||||
|
obj[key] = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
patch: patch
|
||||||
|
};
|
|
@ -0,0 +1,890 @@
|
||||||
|
var $, ColumnDataSource, DEFAULT_TITLE, Document, DocumentChangedEvent, EQ, HasProps, ModelChangedEvent, Models, MultiDict, RootAddedEvent, RootRemovedEvent, Set, Solver, TitleChangedEvent, Variable, _, is_ref, js_version, logger, ref1, ref2,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty,
|
||||||
|
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
Models = require("./base").Models;
|
||||||
|
|
||||||
|
js_version = require("./version");
|
||||||
|
|
||||||
|
ref1 = require("./core/layout/solver"), EQ = ref1.EQ, Solver = ref1.Solver, Variable = ref1.Variable;
|
||||||
|
|
||||||
|
logger = require("./core/logging").logger;
|
||||||
|
|
||||||
|
HasProps = require("./core/has_props");
|
||||||
|
|
||||||
|
is_ref = require("./core/util/refs").is_ref;
|
||||||
|
|
||||||
|
ref2 = require("./core/util/data_structures"), MultiDict = ref2.MultiDict, Set = ref2.Set;
|
||||||
|
|
||||||
|
ColumnDataSource = require("./models/sources/column_data_source");
|
||||||
|
|
||||||
|
DocumentChangedEvent = (function() {
|
||||||
|
function DocumentChangedEvent(document) {
|
||||||
|
this.document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DocumentChangedEvent;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
ModelChangedEvent = (function(superClass) {
|
||||||
|
extend(ModelChangedEvent, superClass);
|
||||||
|
|
||||||
|
function ModelChangedEvent(document, model1, attr1, old1, new_1) {
|
||||||
|
this.document = document;
|
||||||
|
this.model = model1;
|
||||||
|
this.attr = attr1;
|
||||||
|
this.old = old1;
|
||||||
|
this.new_ = new_1;
|
||||||
|
ModelChangedEvent.__super__.constructor.call(this, this.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelChangedEvent.prototype.json = function(references) {
|
||||||
|
var id, value, value_json, value_refs;
|
||||||
|
if (this.attr === 'id') {
|
||||||
|
console.log("'id' field is immutable and should never be in a ModelChangedEvent ", this);
|
||||||
|
throw new Error("'id' field should never change, whatever code just set it is wrong");
|
||||||
|
}
|
||||||
|
value = this.new_;
|
||||||
|
value_json = HasProps._value_to_json('new_', value, this.model);
|
||||||
|
value_refs = {};
|
||||||
|
HasProps._value_record_references(value, value_refs, true);
|
||||||
|
if (this.model.id in value_refs && this.model !== value) {
|
||||||
|
delete value_refs[this.model.id];
|
||||||
|
}
|
||||||
|
for (id in value_refs) {
|
||||||
|
references[id] = value_refs[id];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'kind': 'ModelChanged',
|
||||||
|
'model': this.model.ref(),
|
||||||
|
'attr': this.attr,
|
||||||
|
'new': value_json
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ModelChangedEvent;
|
||||||
|
|
||||||
|
})(DocumentChangedEvent);
|
||||||
|
|
||||||
|
TitleChangedEvent = (function(superClass) {
|
||||||
|
extend(TitleChangedEvent, superClass);
|
||||||
|
|
||||||
|
function TitleChangedEvent(document, title1) {
|
||||||
|
this.document = document;
|
||||||
|
this.title = title1;
|
||||||
|
TitleChangedEvent.__super__.constructor.call(this, this.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleChangedEvent.prototype.json = function(references) {
|
||||||
|
return {
|
||||||
|
'kind': 'TitleChanged',
|
||||||
|
'title': this.title
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return TitleChangedEvent;
|
||||||
|
|
||||||
|
})(DocumentChangedEvent);
|
||||||
|
|
||||||
|
RootAddedEvent = (function(superClass) {
|
||||||
|
extend(RootAddedEvent, superClass);
|
||||||
|
|
||||||
|
function RootAddedEvent(document, model1) {
|
||||||
|
this.document = document;
|
||||||
|
this.model = model1;
|
||||||
|
RootAddedEvent.__super__.constructor.call(this, this.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
RootAddedEvent.prototype.json = function(references) {
|
||||||
|
HasProps._value_record_references(this.model, references, true);
|
||||||
|
return {
|
||||||
|
'kind': 'RootAdded',
|
||||||
|
'model': this.model.ref()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return RootAddedEvent;
|
||||||
|
|
||||||
|
})(DocumentChangedEvent);
|
||||||
|
|
||||||
|
RootRemovedEvent = (function(superClass) {
|
||||||
|
extend(RootRemovedEvent, superClass);
|
||||||
|
|
||||||
|
function RootRemovedEvent(document, model1) {
|
||||||
|
this.document = document;
|
||||||
|
this.model = model1;
|
||||||
|
RootRemovedEvent.__super__.constructor.call(this, this.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
RootRemovedEvent.prototype.json = function(references) {
|
||||||
|
return {
|
||||||
|
'kind': 'RootRemoved',
|
||||||
|
'model': this.model.ref()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return RootRemovedEvent;
|
||||||
|
|
||||||
|
})(DocumentChangedEvent);
|
||||||
|
|
||||||
|
DEFAULT_TITLE = "Bokeh Application";
|
||||||
|
|
||||||
|
Document = (function() {
|
||||||
|
function Document() {
|
||||||
|
this._title = DEFAULT_TITLE;
|
||||||
|
this._roots = [];
|
||||||
|
this._all_models = {};
|
||||||
|
this._all_models_by_name = new MultiDict();
|
||||||
|
this._all_models_freeze_count = 0;
|
||||||
|
this._callbacks = [];
|
||||||
|
this._doc_width = new Variable("document_width");
|
||||||
|
this._doc_height = new Variable("document_height");
|
||||||
|
this._solver = new Solver();
|
||||||
|
this._init_solver();
|
||||||
|
$(window).on("resize", $.proxy(this.resize, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
Document.prototype._init_solver = function() {
|
||||||
|
var j, len, model, ref3, results;
|
||||||
|
this._solver.clear();
|
||||||
|
this._solver.add_edit_variable(this._doc_width);
|
||||||
|
this._solver.add_edit_variable(this._doc_height);
|
||||||
|
ref3 = this._roots;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
model = ref3[j];
|
||||||
|
if (model.layoutable) {
|
||||||
|
results.push(this._add_layoutable(model));
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.solver = function() {
|
||||||
|
return this._solver;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.resize = function() {
|
||||||
|
this._resize();
|
||||||
|
return this._resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._resize = function() {
|
||||||
|
var height, j, len, measuring, ref3, root, root_div, target_height, vars, width;
|
||||||
|
ref3 = this._roots;
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
root = ref3[j];
|
||||||
|
if (root.layoutable !== true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vars = root.get_constrained_variables();
|
||||||
|
if ((vars.width == null) && (vars.height == null)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
root_div = $("#modelid_" + root.id);
|
||||||
|
target_height = 0;
|
||||||
|
measuring = root_div;
|
||||||
|
while (target_height === 0) {
|
||||||
|
measuring = measuring.parent();
|
||||||
|
target_height = measuring.height();
|
||||||
|
}
|
||||||
|
width = measuring.width();
|
||||||
|
height = target_height;
|
||||||
|
if (vars.width != null) {
|
||||||
|
logger.debug("Suggest width on Document -- " + width);
|
||||||
|
this._solver.suggest_value(this._doc_width, width);
|
||||||
|
}
|
||||||
|
if (vars.height != null) {
|
||||||
|
logger.debug("Suggest height on Document -- " + height);
|
||||||
|
this._solver.suggest_value(this._doc_height, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._solver.update_variables(false);
|
||||||
|
return this._solver.trigger('resize');
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.clear = function() {
|
||||||
|
var results;
|
||||||
|
this._push_all_models_freeze();
|
||||||
|
try {
|
||||||
|
results = [];
|
||||||
|
while (this._roots.length > 0) {
|
||||||
|
results.push(this.remove_root(this._roots[0]));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} finally {
|
||||||
|
this._pop_all_models_freeze();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._destructively_move = function(dest_doc) {
|
||||||
|
var j, l, len, len1, r, roots;
|
||||||
|
if (dest_doc === this) {
|
||||||
|
throw new Error("Attempted to overwrite a document with itself");
|
||||||
|
}
|
||||||
|
dest_doc.clear();
|
||||||
|
roots = [];
|
||||||
|
this._push_all_models_freeze();
|
||||||
|
try {
|
||||||
|
while (this._roots.length > 0) {
|
||||||
|
this.remove_root(this._roots[0]);
|
||||||
|
roots.push(r);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this._pop_all_models_freeze();
|
||||||
|
}
|
||||||
|
for (j = 0, len = roots.length; j < len; j++) {
|
||||||
|
r = roots[j];
|
||||||
|
if (r.document !== null) {
|
||||||
|
throw new Error("Somehow we didn't detach " + r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_all_models.length !== 0) {
|
||||||
|
throw new Error("_all_models still had stuff in it: " + this._all_models);
|
||||||
|
}
|
||||||
|
for (l = 0, len1 = roots.length; l < len1; l++) {
|
||||||
|
r = roots[l];
|
||||||
|
dest_doc.add_root(r);
|
||||||
|
}
|
||||||
|
return dest_doc.set_title(this._title);
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._push_all_models_freeze = function() {
|
||||||
|
return this._all_models_freeze_count += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._pop_all_models_freeze = function() {
|
||||||
|
this._all_models_freeze_count -= 1;
|
||||||
|
if (this._all_models_freeze_count === 0) {
|
||||||
|
return this._recompute_all_models();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._invalidate_all_models = function() {
|
||||||
|
logger.debug("invalidating document models");
|
||||||
|
if (this._all_models_freeze_count === 0) {
|
||||||
|
return this._recompute_all_models();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._recompute_all_models = function() {
|
||||||
|
var a, d, j, l, len, len1, len2, len3, m, n, name, new_all_models_set, o, old_all_models_set, r, recomputed, ref3, ref4, ref5, ref6, to_attach, to_detach;
|
||||||
|
new_all_models_set = new Set();
|
||||||
|
ref3 = this._roots;
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
r = ref3[j];
|
||||||
|
new_all_models_set = new_all_models_set.union(r.references());
|
||||||
|
}
|
||||||
|
old_all_models_set = new Set(_.values(this._all_models));
|
||||||
|
to_detach = old_all_models_set.diff(new_all_models_set);
|
||||||
|
to_attach = new_all_models_set.diff(old_all_models_set);
|
||||||
|
recomputed = {};
|
||||||
|
ref4 = new_all_models_set.values;
|
||||||
|
for (l = 0, len1 = ref4.length; l < len1; l++) {
|
||||||
|
m = ref4[l];
|
||||||
|
recomputed[m.id] = m;
|
||||||
|
}
|
||||||
|
ref5 = to_detach.values;
|
||||||
|
for (n = 0, len2 = ref5.length; n < len2; n++) {
|
||||||
|
d = ref5[n];
|
||||||
|
d.detach_document();
|
||||||
|
name = d.get('name');
|
||||||
|
if (name !== null) {
|
||||||
|
this._all_models_by_name.remove_value(name, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref6 = to_attach.values;
|
||||||
|
for (o = 0, len3 = ref6.length; o < len3; o++) {
|
||||||
|
a = ref6[o];
|
||||||
|
a.attach_document(this);
|
||||||
|
name = a.get('name');
|
||||||
|
if (name !== null) {
|
||||||
|
this._all_models_by_name.add_value(name, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._all_models = recomputed;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.roots = function() {
|
||||||
|
return this._roots;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._add_layoutable = function(model) {
|
||||||
|
var constraint, constraints, edit_variable, editables, j, l, len, len1, ref3, strength, vars;
|
||||||
|
if (model.layoutable !== true) {
|
||||||
|
throw new Error("Cannot add non-layoutable - " + model);
|
||||||
|
}
|
||||||
|
editables = model.get_edit_variables();
|
||||||
|
constraints = model.get_constraints();
|
||||||
|
vars = model.get_constrained_variables();
|
||||||
|
for (j = 0, len = editables.length; j < len; j++) {
|
||||||
|
ref3 = editables[j], edit_variable = ref3.edit_variable, strength = ref3.strength;
|
||||||
|
this._solver.add_edit_variable(edit_variable, strength);
|
||||||
|
}
|
||||||
|
for (l = 0, len1 = constraints.length; l < len1; l++) {
|
||||||
|
constraint = constraints[l];
|
||||||
|
this._solver.add_constraint(constraint);
|
||||||
|
}
|
||||||
|
if (vars.width != null) {
|
||||||
|
this._solver.add_constraint(EQ(vars.width, this._doc_width));
|
||||||
|
}
|
||||||
|
if (vars.height != null) {
|
||||||
|
this._solver.add_constraint(EQ(vars.height, this._doc_height));
|
||||||
|
}
|
||||||
|
return this._solver.update_variables();
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.add_root = function(model) {
|
||||||
|
logger.debug("Adding root: " + model);
|
||||||
|
if (indexOf.call(this._roots, model) >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._push_all_models_freeze();
|
||||||
|
try {
|
||||||
|
this._roots.push(model);
|
||||||
|
model._is_root = true;
|
||||||
|
} finally {
|
||||||
|
this._pop_all_models_freeze();
|
||||||
|
}
|
||||||
|
this._init_solver();
|
||||||
|
return this._trigger_on_change(new RootAddedEvent(this, model));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.remove_root = function(model) {
|
||||||
|
var i;
|
||||||
|
i = this._roots.indexOf(model);
|
||||||
|
if (i < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._push_all_models_freeze();
|
||||||
|
try {
|
||||||
|
this._roots.splice(i, 1);
|
||||||
|
model._is_root = false;
|
||||||
|
} finally {
|
||||||
|
this._pop_all_models_freeze();
|
||||||
|
}
|
||||||
|
this._init_solver();
|
||||||
|
return this._trigger_on_change(new RootRemovedEvent(this, model));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.title = function() {
|
||||||
|
return this._title;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.set_title = function(title) {
|
||||||
|
if (title !== this._title) {
|
||||||
|
this._title = title;
|
||||||
|
return this._trigger_on_change(new TitleChangedEvent(this, title));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.get_model_by_id = function(model_id) {
|
||||||
|
if (model_id in this._all_models) {
|
||||||
|
return this._all_models[model_id];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.get_model_by_name = function(name) {
|
||||||
|
return this._all_models_by_name.get_one(name, "Multiple models are named '" + name + "'");
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.on_change = function(callback) {
|
||||||
|
if (indexOf.call(this._callbacks, callback) >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this._callbacks.push(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.remove_on_change = function(callback) {
|
||||||
|
var i;
|
||||||
|
i = this._callbacks.indexOf(callback);
|
||||||
|
if (i >= 0) {
|
||||||
|
return this._callbacks.splice(i, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._trigger_on_change = function(event) {
|
||||||
|
var cb, j, len, ref3, results;
|
||||||
|
ref3 = this._callbacks;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
cb = ref3[j];
|
||||||
|
results.push(cb(event));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype._notify_change = function(model, attr, old, new_) {
|
||||||
|
if (attr === 'name') {
|
||||||
|
this._all_models_by_name.remove_value(old, model);
|
||||||
|
if (new_ !== null) {
|
||||||
|
this._all_models_by_name.add_value(new_, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._trigger_on_change(new ModelChangedEvent(this, model, attr, old, new_));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._references_json = function(references, include_defaults) {
|
||||||
|
var j, len, r, ref, references_json;
|
||||||
|
if (include_defaults == null) {
|
||||||
|
include_defaults = true;
|
||||||
|
}
|
||||||
|
references_json = [];
|
||||||
|
for (j = 0, len = references.length; j < len; j++) {
|
||||||
|
r = references[j];
|
||||||
|
ref = r.ref();
|
||||||
|
ref['attributes'] = r.attributes_as_json(include_defaults);
|
||||||
|
delete ref['attributes']['id'];
|
||||||
|
references_json.push(ref);
|
||||||
|
}
|
||||||
|
return references_json;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._instantiate_object = function(obj_id, obj_type, obj_attrs) {
|
||||||
|
var full_attrs, model;
|
||||||
|
full_attrs = _.extend({}, obj_attrs, {
|
||||||
|
id: obj_id
|
||||||
|
});
|
||||||
|
model = Models(obj_type);
|
||||||
|
return new model(full_attrs, {
|
||||||
|
silent: true,
|
||||||
|
defer_initialization: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._instantiate_references_json = function(references_json, existing_models) {
|
||||||
|
var instance, j, len, obj, obj_attrs, obj_id, obj_type, references;
|
||||||
|
references = {};
|
||||||
|
for (j = 0, len = references_json.length; j < len; j++) {
|
||||||
|
obj = references_json[j];
|
||||||
|
obj_id = obj['id'];
|
||||||
|
obj_type = obj['type'];
|
||||||
|
obj_attrs = obj['attributes'];
|
||||||
|
if (obj_id in existing_models) {
|
||||||
|
instance = existing_models[obj_id];
|
||||||
|
} else {
|
||||||
|
instance = Document._instantiate_object(obj_id, obj_type, obj_attrs);
|
||||||
|
if ('subtype' in obj) {
|
||||||
|
instance.set_subtype(obj['subtype']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
references[instance.id] = instance;
|
||||||
|
}
|
||||||
|
return references;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._resolve_refs = function(value, old_references, new_references) {
|
||||||
|
var resolve_array, resolve_dict, resolve_ref;
|
||||||
|
resolve_ref = function(v) {
|
||||||
|
if (is_ref(v)) {
|
||||||
|
if (v['id'] in old_references) {
|
||||||
|
return old_references[v['id']];
|
||||||
|
} else if (v['id'] in new_references) {
|
||||||
|
return new_references[v['id']];
|
||||||
|
} else {
|
||||||
|
throw new Error("reference " + (JSON.stringify(v)) + " isn't known (not in Document?)");
|
||||||
|
}
|
||||||
|
} else if (_.isArray(v)) {
|
||||||
|
return resolve_array(v);
|
||||||
|
} else if (_.isObject(v)) {
|
||||||
|
return resolve_dict(v);
|
||||||
|
} else {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
resolve_dict = function(dict) {
|
||||||
|
var k, resolved, v;
|
||||||
|
resolved = {};
|
||||||
|
for (k in dict) {
|
||||||
|
v = dict[k];
|
||||||
|
resolved[k] = resolve_ref(v);
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
};
|
||||||
|
resolve_array = function(array) {
|
||||||
|
var j, len, results, v;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = array.length; j < len; j++) {
|
||||||
|
v = array[j];
|
||||||
|
results.push(resolve_ref(v));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
return resolve_ref(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._initialize_references_json = function(references_json, old_references, new_references) {
|
||||||
|
var foreach_depth_first, instance, j, len, obj, obj_attrs, obj_id, to_update, was_new;
|
||||||
|
to_update = {};
|
||||||
|
for (j = 0, len = references_json.length; j < len; j++) {
|
||||||
|
obj = references_json[j];
|
||||||
|
obj_id = obj['id'];
|
||||||
|
obj_attrs = obj['attributes'];
|
||||||
|
was_new = false;
|
||||||
|
instance = obj_id in old_references ? old_references[obj_id] : (was_new = true, new_references[obj_id]);
|
||||||
|
obj_attrs = Document._resolve_refs(obj_attrs, old_references, new_references);
|
||||||
|
to_update[instance.id] = [instance, obj_attrs, was_new];
|
||||||
|
}
|
||||||
|
foreach_depth_first = function(items, f) {
|
||||||
|
var already_started, foreach_value, k, results, v;
|
||||||
|
already_started = {};
|
||||||
|
foreach_value = function(v, f) {
|
||||||
|
var a, attrs, e, k, l, len1, ref3, results, results1, same_as_v;
|
||||||
|
if (v instanceof HasProps) {
|
||||||
|
if (!(v.id in already_started) && v.id in items) {
|
||||||
|
already_started[v.id] = true;
|
||||||
|
ref3 = items[v.id], same_as_v = ref3[0], attrs = ref3[1], was_new = ref3[2];
|
||||||
|
for (a in attrs) {
|
||||||
|
e = attrs[a];
|
||||||
|
foreach_value(e, f);
|
||||||
|
}
|
||||||
|
return f(v, attrs, was_new);
|
||||||
|
}
|
||||||
|
} else if (_.isArray(v)) {
|
||||||
|
results = [];
|
||||||
|
for (l = 0, len1 = v.length; l < len1; l++) {
|
||||||
|
e = v[l];
|
||||||
|
results.push(foreach_value(e, f));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} else if (_.isObject(v)) {
|
||||||
|
results1 = [];
|
||||||
|
for (k in v) {
|
||||||
|
e = v[k];
|
||||||
|
results1.push(foreach_value(e, f));
|
||||||
|
}
|
||||||
|
return results1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
results = [];
|
||||||
|
for (k in items) {
|
||||||
|
v = items[k];
|
||||||
|
results.push(foreach_value(v[0], f));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
foreach_depth_first(to_update, function(instance, attrs, was_new) {
|
||||||
|
if (was_new) {
|
||||||
|
return instance.set(attrs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return foreach_depth_first(to_update, function(instance, attrs, was_new) {
|
||||||
|
if (was_new) {
|
||||||
|
return instance.initialize(attrs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._event_for_attribute_change = function(changed_obj, key, new_value, doc, value_refs) {
|
||||||
|
var changed_model, event;
|
||||||
|
changed_model = doc.get_model_by_id(changed_obj.id);
|
||||||
|
if (!changed_model.attribute_is_serializable(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
event = {
|
||||||
|
'kind': 'ModelChanged',
|
||||||
|
'model': {
|
||||||
|
id: changed_obj.id,
|
||||||
|
type: changed_obj.type
|
||||||
|
},
|
||||||
|
'attr': key,
|
||||||
|
'new': new_value
|
||||||
|
};
|
||||||
|
HasProps._json_record_references(doc, new_value, value_refs, true);
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._events_to_sync_objects = function(from_obj, to_obj, to_doc, value_refs) {
|
||||||
|
var added, events, from_keys, j, key, l, len, len1, len2, n, new_value, old_value, removed, shared, to_keys;
|
||||||
|
from_keys = Object.keys(from_obj.attributes);
|
||||||
|
to_keys = Object.keys(to_obj.attributes);
|
||||||
|
removed = _.difference(from_keys, to_keys);
|
||||||
|
added = _.difference(to_keys, from_keys);
|
||||||
|
shared = _.intersection(from_keys, to_keys);
|
||||||
|
events = [];
|
||||||
|
for (j = 0, len = removed.length; j < len; j++) {
|
||||||
|
key = removed[j];
|
||||||
|
logger.warn("Server sent key " + key + " but we don't seem to have it in our JSON");
|
||||||
|
}
|
||||||
|
for (l = 0, len1 = added.length; l < len1; l++) {
|
||||||
|
key = added[l];
|
||||||
|
new_value = to_obj.attributes[key];
|
||||||
|
events.push(Document._event_for_attribute_change(from_obj, key, new_value, to_doc, value_refs));
|
||||||
|
}
|
||||||
|
for (n = 0, len2 = shared.length; n < len2; n++) {
|
||||||
|
key = shared[n];
|
||||||
|
old_value = from_obj.attributes[key];
|
||||||
|
new_value = to_obj.attributes[key];
|
||||||
|
if (old_value === null && new_value === null) {
|
||||||
|
|
||||||
|
} else if (old_value === null || new_value === null) {
|
||||||
|
events.push(Document._event_for_attribute_change(from_obj, key, new_value, to_doc, value_refs));
|
||||||
|
} else {
|
||||||
|
if (!_.isEqual(old_value, new_value)) {
|
||||||
|
events.push(Document._event_for_attribute_change(from_obj, key, new_value, to_doc, value_refs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _.filter(events, function(e) {
|
||||||
|
return e !== null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Document._compute_patch_since_json = function(from_json, to_doc) {
|
||||||
|
var events, from_references, from_root_ids, from_roots, id, include_defaults, j, l, len, len1, model, r, ref3, ref4, ref5, refs, to_json, to_references, to_root_ids, to_roots, update_model_events, value_refs;
|
||||||
|
to_json = to_doc.to_json(include_defaults = false);
|
||||||
|
refs = function(json) {
|
||||||
|
var j, len, obj, ref3, result;
|
||||||
|
result = {};
|
||||||
|
ref3 = json['roots']['references'];
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
obj = ref3[j];
|
||||||
|
result[obj.id] = obj;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
from_references = refs(from_json);
|
||||||
|
from_roots = {};
|
||||||
|
from_root_ids = [];
|
||||||
|
ref3 = from_json['roots']['root_ids'];
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
r = ref3[j];
|
||||||
|
from_roots[r] = from_references[r];
|
||||||
|
from_root_ids.push(r);
|
||||||
|
}
|
||||||
|
to_references = refs(to_json);
|
||||||
|
to_roots = {};
|
||||||
|
to_root_ids = [];
|
||||||
|
ref4 = to_json['roots']['root_ids'];
|
||||||
|
for (l = 0, len1 = ref4.length; l < len1; l++) {
|
||||||
|
r = ref4[l];
|
||||||
|
to_roots[r] = to_references[r];
|
||||||
|
to_root_ids.push(r);
|
||||||
|
}
|
||||||
|
from_root_ids.sort();
|
||||||
|
to_root_ids.sort();
|
||||||
|
if (_.difference(from_root_ids, to_root_ids).length > 0 || _.difference(to_root_ids, from_root_ids).length > 0) {
|
||||||
|
throw new Error("Not implemented: computing add/remove of document roots");
|
||||||
|
}
|
||||||
|
value_refs = {};
|
||||||
|
events = [];
|
||||||
|
ref5 = to_doc._all_models;
|
||||||
|
for (id in ref5) {
|
||||||
|
model = ref5[id];
|
||||||
|
if (id in from_references) {
|
||||||
|
update_model_events = Document._events_to_sync_objects(from_references[id], to_references[id], to_doc, value_refs);
|
||||||
|
events = events.concat(update_model_events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'events': events,
|
||||||
|
'references': Document._references_json(_.values(value_refs), include_defaults = false)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.to_json_string = function(include_defaults) {
|
||||||
|
if (include_defaults == null) {
|
||||||
|
include_defaults = true;
|
||||||
|
}
|
||||||
|
return JSON.stringify(this.to_json(include_defaults));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.to_json = function(include_defaults) {
|
||||||
|
var j, len, r, ref3, root_ids, root_references;
|
||||||
|
if (include_defaults == null) {
|
||||||
|
include_defaults = true;
|
||||||
|
}
|
||||||
|
root_ids = [];
|
||||||
|
ref3 = this._roots;
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
r = ref3[j];
|
||||||
|
root_ids.push(r.id);
|
||||||
|
}
|
||||||
|
root_references = _.values(this._all_models);
|
||||||
|
return {
|
||||||
|
'title': this._title,
|
||||||
|
'roots': {
|
||||||
|
'root_ids': root_ids,
|
||||||
|
'references': Document._references_json(root_references, include_defaults)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.from_json_string = function(s) {
|
||||||
|
var json;
|
||||||
|
if (s === null || (s == null)) {
|
||||||
|
throw new Error("JSON string is " + (typeof s));
|
||||||
|
}
|
||||||
|
json = JSON.parse(s);
|
||||||
|
return Document.from_json(json);
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.from_json = function(json) {
|
||||||
|
var doc, j, len, py_version, r, references, references_json, root_ids, roots_json, versions_string;
|
||||||
|
logger.debug("Creating Document from JSON");
|
||||||
|
if (typeof json !== 'object') {
|
||||||
|
throw new Error("JSON object has wrong type " + (typeof json));
|
||||||
|
}
|
||||||
|
py_version = json['version'];
|
||||||
|
versions_string = "Library versions: JS (" + js_version + ") / Python (" + py_version + ")";
|
||||||
|
if (py_version.indexOf('-') < 0 && js_version !== py_version) {
|
||||||
|
logger.warn("JS/Python version mismatch");
|
||||||
|
logger.warn(versions_string);
|
||||||
|
} else {
|
||||||
|
logger.debug(versions_string);
|
||||||
|
}
|
||||||
|
roots_json = json['roots'];
|
||||||
|
root_ids = roots_json['root_ids'];
|
||||||
|
references_json = roots_json['references'];
|
||||||
|
references = Document._instantiate_references_json(references_json, {});
|
||||||
|
Document._initialize_references_json(references_json, {}, references);
|
||||||
|
doc = new Document();
|
||||||
|
for (j = 0, len = root_ids.length; j < len; j++) {
|
||||||
|
r = root_ids[j];
|
||||||
|
doc.add_root(references[r]);
|
||||||
|
}
|
||||||
|
doc.set_title(json['title']);
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.replace_with_json = function(json) {
|
||||||
|
var replacement;
|
||||||
|
replacement = Document.from_json(json);
|
||||||
|
return replacement._destructively_move(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.create_json_patch_string = function(events) {
|
||||||
|
return JSON.stringify(this.create_json_patch(events));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.create_json_patch = function(events) {
|
||||||
|
var event, j, json_events, len, references, result;
|
||||||
|
references = {};
|
||||||
|
json_events = [];
|
||||||
|
for (j = 0, len = events.length; j < len; j++) {
|
||||||
|
event = events[j];
|
||||||
|
if (event.document !== this) {
|
||||||
|
console.log("Cannot create a patch using events from a different document, event had ", event.document, " we are ", this);
|
||||||
|
throw new Error("Cannot create a patch using events from a different document");
|
||||||
|
}
|
||||||
|
json_events.push(event.json(references));
|
||||||
|
}
|
||||||
|
return result = {
|
||||||
|
events: json_events,
|
||||||
|
references: Document._references_json(_.values(references))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.apply_json_patch_string = function(patch) {
|
||||||
|
return this.apply_json_patch(JSON.parse(patch));
|
||||||
|
};
|
||||||
|
|
||||||
|
Document.prototype.apply_json_patch = function(patch) {
|
||||||
|
var attr, column_source, column_source_id, data, event_json, events_json, id, j, l, len, len1, model_id, new_references, obj1, old_references, patched_id, patched_obj, patches, references, references_json, results, rollover, root_id, root_obj, value;
|
||||||
|
references_json = patch['references'];
|
||||||
|
events_json = patch['events'];
|
||||||
|
references = Document._instantiate_references_json(references_json, this._all_models);
|
||||||
|
for (j = 0, len = events_json.length; j < len; j++) {
|
||||||
|
event_json = events_json[j];
|
||||||
|
if ('model' in event_json) {
|
||||||
|
model_id = event_json['model']['id'];
|
||||||
|
if (model_id in this._all_models) {
|
||||||
|
references[model_id] = this._all_models[model_id];
|
||||||
|
} else {
|
||||||
|
if (!(model_id in references)) {
|
||||||
|
console.log("Got an event for unknown model ", event_json['model']);
|
||||||
|
throw new Error("event model wasn't known");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_references = {};
|
||||||
|
new_references = {};
|
||||||
|
for (id in references) {
|
||||||
|
value = references[id];
|
||||||
|
if (id in this._all_models) {
|
||||||
|
old_references[id] = value;
|
||||||
|
} else {
|
||||||
|
new_references[id] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Document._initialize_references_json(references_json, old_references, new_references);
|
||||||
|
results = [];
|
||||||
|
for (l = 0, len1 = events_json.length; l < len1; l++) {
|
||||||
|
event_json = events_json[l];
|
||||||
|
if (event_json['kind'] === 'ModelChanged') {
|
||||||
|
patched_id = event_json['model']['id'];
|
||||||
|
if (!(patched_id in this._all_models)) {
|
||||||
|
throw new Error("Cannot apply patch to " + patched_id + " which is not in the document");
|
||||||
|
}
|
||||||
|
patched_obj = this._all_models[patched_id];
|
||||||
|
attr = event_json['attr'];
|
||||||
|
value = Document._resolve_refs(event_json['new'], old_references, new_references);
|
||||||
|
results.push(patched_obj.set((
|
||||||
|
obj1 = {},
|
||||||
|
obj1["" + attr] = value,
|
||||||
|
obj1
|
||||||
|
)));
|
||||||
|
} else if (event_json['kind'] === 'ColumnsStreamed') {
|
||||||
|
column_source_id = event_json['column_source']['id'];
|
||||||
|
if (!(column_source_id in this._all_models)) {
|
||||||
|
throw new Error("Cannot stream to " + column_source_id + " which is not in the document");
|
||||||
|
}
|
||||||
|
column_source = this._all_models[column_source_id];
|
||||||
|
if (!(column_source instanceof ColumnDataSource.Model)) {
|
||||||
|
throw new Error("Cannot stream to non-ColumnDataSource");
|
||||||
|
}
|
||||||
|
data = event_json['data'];
|
||||||
|
rollover = event_json['rollover'];
|
||||||
|
results.push(column_source.stream(data, rollover));
|
||||||
|
} else if (event_json['kind'] === 'ColumnsPatched') {
|
||||||
|
column_source_id = event_json['column_source']['id'];
|
||||||
|
if (!(column_source_id in this._all_models)) {
|
||||||
|
throw new Error("Cannot patch " + column_source_id + " which is not in the document");
|
||||||
|
}
|
||||||
|
column_source = this._all_models[column_source_id];
|
||||||
|
if (!(column_source instanceof ColumnDataSource.Model)) {
|
||||||
|
throw new Error("Cannot patch non-ColumnDataSource");
|
||||||
|
}
|
||||||
|
patches = event_json['patches'];
|
||||||
|
results.push(column_source.patch(patches));
|
||||||
|
} else if (event_json['kind'] === 'RootAdded') {
|
||||||
|
root_id = event_json['model']['id'];
|
||||||
|
root_obj = references[root_id];
|
||||||
|
results.push(this.add_root(root_obj));
|
||||||
|
} else if (event_json['kind'] === 'RootRemoved') {
|
||||||
|
root_id = event_json['model']['id'];
|
||||||
|
root_obj = references[root_id];
|
||||||
|
results.push(this.remove_root(root_obj));
|
||||||
|
} else if (event_json['kind'] === 'TitleChanged') {
|
||||||
|
results.push(this.set_title(event_json['title']));
|
||||||
|
} else {
|
||||||
|
throw new Error("Unknown patch event " + JSON.stringify(event_json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Document;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Document: Document,
|
||||||
|
DocumentChangedEvent: DocumentChangedEvent,
|
||||||
|
ModelChangedEvent: ModelChangedEvent,
|
||||||
|
TitleChangedEvent: TitleChangedEvent,
|
||||||
|
RootAddedEvent: RootAddedEvent,
|
||||||
|
RootRemovedEvent: RootRemovedEvent,
|
||||||
|
DEFAULT_TITLE: DEFAULT_TITLE
|
||||||
|
};
|
|
@ -0,0 +1,285 @@
|
||||||
|
var $, BOKEH_ROOT, Backbone, Document, Promise, RootAddedEvent, RootRemovedEvent, TitleChangedEvent, _, _create_view, _get_session, _handle_notebook_comms, _init_comms, _render_document_to_element, _sessions, _update_comms_callback, add_document_from_session, add_document_standalone, add_document_static, add_model_from_session, add_model_static, base, embed_items, fill_render_item_from_script_tag, inject_css, inject_raw_css, logger, pull_session, ref, ref1, set_log_level;
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Backbone = require("backbone");
|
||||||
|
|
||||||
|
Promise = require("es6-promise").Promise;
|
||||||
|
|
||||||
|
base = require("./base");
|
||||||
|
|
||||||
|
pull_session = require("./client").pull_session;
|
||||||
|
|
||||||
|
ref = require("./core/logging"), logger = ref.logger, set_log_level = ref.set_log_level;
|
||||||
|
|
||||||
|
ref1 = require("./document"), Document = ref1.Document, RootAddedEvent = ref1.RootAddedEvent, RootRemovedEvent = ref1.RootRemovedEvent, TitleChangedEvent = ref1.TitleChangedEvent;
|
||||||
|
|
||||||
|
BOKEH_ROOT = "bk-root";
|
||||||
|
|
||||||
|
_handle_notebook_comms = function(msg) {
|
||||||
|
var data;
|
||||||
|
logger.debug("handling notebook comms");
|
||||||
|
data = JSON.parse(msg.content.data);
|
||||||
|
if ('events' in data && 'references' in data) {
|
||||||
|
return this.apply_json_patch(data);
|
||||||
|
} else if ('doc' in data) {
|
||||||
|
return this.replace_with_json(data['doc']);
|
||||||
|
} else {
|
||||||
|
throw new Error("handling notebook comms message: ", msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_update_comms_callback = function(target, doc, comm) {
|
||||||
|
if (target === comm.target_name) {
|
||||||
|
return comm.on_msg(_.bind(_handle_notebook_comms, doc));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_init_comms = function(target, doc) {
|
||||||
|
var comm_manager, e, error1, id, promise, ref2, update_comms;
|
||||||
|
if ((typeof Jupyter !== "undefined" && Jupyter !== null) && (Jupyter.notebook.kernel != null)) {
|
||||||
|
logger.info("Registering Jupyter comms for target " + target);
|
||||||
|
comm_manager = Jupyter.notebook.kernel.comm_manager;
|
||||||
|
update_comms = _.partial(_update_comms_callback, target, doc);
|
||||||
|
ref2 = comm_manager.comms;
|
||||||
|
for (id in ref2) {
|
||||||
|
promise = ref2[id];
|
||||||
|
promise.then(update_comms);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return comm_manager.register_target(target, function(comm, msg) {
|
||||||
|
logger.info("Registering Jupyter comms for target " + target);
|
||||||
|
return comm.on_msg(_.bind(_handle_notebook_comms, doc));
|
||||||
|
});
|
||||||
|
} catch (error1) {
|
||||||
|
e = error1;
|
||||||
|
return logger.warn("Jupyter comms failed to register. push_notebook() will not function. (exception reported: " + e + ")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return console.warn('Jupyter notebooks comms not available. push_notebook() will not function');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_create_view = function(model) {
|
||||||
|
var view;
|
||||||
|
view = new model.default_view({
|
||||||
|
model: model
|
||||||
|
});
|
||||||
|
base.index[model.id] = view;
|
||||||
|
return view;
|
||||||
|
};
|
||||||
|
|
||||||
|
_render_document_to_element = function(element, document, use_for_title) {
|
||||||
|
var i, len, model, ref2, render_model, unrender_model, views;
|
||||||
|
views = {};
|
||||||
|
render_model = function(model) {
|
||||||
|
var view;
|
||||||
|
view = _create_view(model);
|
||||||
|
views[model.id] = view;
|
||||||
|
return $(element).append(view.$el);
|
||||||
|
};
|
||||||
|
unrender_model = function(model) {
|
||||||
|
var view;
|
||||||
|
if (model.id in views) {
|
||||||
|
view = views[model.id];
|
||||||
|
$(element).remove(view.$el);
|
||||||
|
delete views[model.id];
|
||||||
|
return delete base.index[model.id];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ref2 = document.roots();
|
||||||
|
for (i = 0, len = ref2.length; i < len; i++) {
|
||||||
|
model = ref2[i];
|
||||||
|
render_model(model);
|
||||||
|
}
|
||||||
|
if (use_for_title) {
|
||||||
|
window.document.title = document.title();
|
||||||
|
}
|
||||||
|
document.on_change(function(event) {
|
||||||
|
if (event instanceof RootAddedEvent) {
|
||||||
|
return render_model(event.model);
|
||||||
|
} else if (event instanceof RootRemovedEvent) {
|
||||||
|
return unrender_model(event.model);
|
||||||
|
} else if (use_for_title && event instanceof TitleChangedEvent) {
|
||||||
|
return window.document.title = event.title;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return views;
|
||||||
|
};
|
||||||
|
|
||||||
|
add_model_static = function(element, model_id, doc) {
|
||||||
|
var model, view;
|
||||||
|
model = doc.get_model_by_id(model_id);
|
||||||
|
if (model == null) {
|
||||||
|
throw new Error("Model " + model_id + " was not in document " + doc);
|
||||||
|
}
|
||||||
|
view = _create_view(model);
|
||||||
|
return _.delay(function() {
|
||||||
|
return $(element).replaceWith(view.$el);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
add_document_static = function(element, doc, use_for_title) {
|
||||||
|
return _.delay(function() {
|
||||||
|
return _render_document_to_element($(element), doc, use_for_title);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
add_document_standalone = function(document, element, use_for_title) {
|
||||||
|
if (use_for_title == null) {
|
||||||
|
use_for_title = false;
|
||||||
|
}
|
||||||
|
return _render_document_to_element($(element), document, use_for_title);
|
||||||
|
};
|
||||||
|
|
||||||
|
_sessions = {};
|
||||||
|
|
||||||
|
_get_session = function(websocket_url, session_id) {
|
||||||
|
var subsessions;
|
||||||
|
if ((websocket_url == null) || websocket_url === null) {
|
||||||
|
throw new Error("Missing websocket_url");
|
||||||
|
}
|
||||||
|
if (!(websocket_url in _sessions)) {
|
||||||
|
_sessions[websocket_url] = {};
|
||||||
|
}
|
||||||
|
subsessions = _sessions[websocket_url];
|
||||||
|
if (!(session_id in subsessions)) {
|
||||||
|
subsessions[session_id] = pull_session(websocket_url, session_id);
|
||||||
|
}
|
||||||
|
return subsessions[session_id];
|
||||||
|
};
|
||||||
|
|
||||||
|
add_document_from_session = function(element, websocket_url, session_id, use_for_title) {
|
||||||
|
var promise;
|
||||||
|
promise = _get_session(websocket_url, session_id);
|
||||||
|
return promise.then(function(session) {
|
||||||
|
return _render_document_to_element(element, session.document, use_for_title);
|
||||||
|
}, function(error) {
|
||||||
|
logger.error("Failed to load Bokeh session " + session_id + ": " + error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
add_model_from_session = function(element, websocket_url, model_id, session_id) {
|
||||||
|
var promise;
|
||||||
|
promise = _get_session(websocket_url, session_id);
|
||||||
|
return promise.then(function(session) {
|
||||||
|
var model, view;
|
||||||
|
model = session.document.get_model_by_id(model_id);
|
||||||
|
if (model == null) {
|
||||||
|
throw new Error("Did not find model " + model_id + " in session");
|
||||||
|
}
|
||||||
|
view = _create_view(model);
|
||||||
|
return $(element).replaceWith(view.$el);
|
||||||
|
}, function(error) {
|
||||||
|
logger.error("Failed to load Bokeh session " + session_id + ": " + error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
inject_css = function(url) {
|
||||||
|
var link;
|
||||||
|
link = $("<link href='" + url + "' rel='stylesheet' type='text/css'>");
|
||||||
|
return $('body').append(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
inject_raw_css = function(css) {
|
||||||
|
var style;
|
||||||
|
style = $("<style>").html(css);
|
||||||
|
return $('body').append(style);
|
||||||
|
};
|
||||||
|
|
||||||
|
fill_render_item_from_script_tag = function(script, item) {
|
||||||
|
var info;
|
||||||
|
info = script.data();
|
||||||
|
if ((info.bokehLogLevel != null) && info.bokehLogLevel.length > 0) {
|
||||||
|
set_log_level(info.bokehLogLevel);
|
||||||
|
}
|
||||||
|
if ((info.bokehDocId != null) && info.bokehDocId.length > 0) {
|
||||||
|
item['docid'] = info.bokehDocId;
|
||||||
|
}
|
||||||
|
if ((info.bokehModelId != null) && info.bokehModelId.length > 0) {
|
||||||
|
item['modelid'] = info.bokehModelId;
|
||||||
|
}
|
||||||
|
if ((info.bokehSessionId != null) && info.bokehSessionId.length > 0) {
|
||||||
|
item['sessionid'] = info.bokehSessionId;
|
||||||
|
}
|
||||||
|
return logger.info("Will inject Bokeh script tag with params " + (JSON.stringify(item)));
|
||||||
|
};
|
||||||
|
|
||||||
|
embed_items = function(docs_json, render_items, websocket_url) {
|
||||||
|
var container, docid, docs, elem, element_id, i, item, len, promise, results, use_for_title;
|
||||||
|
if (websocket_url == null) {
|
||||||
|
websocket_url = null;
|
||||||
|
}
|
||||||
|
docs = {};
|
||||||
|
for (docid in docs_json) {
|
||||||
|
docs[docid] = Document.from_json(docs_json[docid]);
|
||||||
|
}
|
||||||
|
results = [];
|
||||||
|
for (i = 0, len = render_items.length; i < len; i++) {
|
||||||
|
item = render_items[i];
|
||||||
|
if (item.notebook_comms_target != null) {
|
||||||
|
_init_comms(item.notebook_comms_target, docs[docid]);
|
||||||
|
}
|
||||||
|
element_id = item['elementid'];
|
||||||
|
elem = $('#' + element_id);
|
||||||
|
if (elem.length === 0) {
|
||||||
|
throw new Error("Error rendering Bokeh model: could not find tag with id: " + element_id);
|
||||||
|
}
|
||||||
|
if (elem.length > 1) {
|
||||||
|
throw new Error("Error rendering Bokeh model: found too many tags with id: " + element_id);
|
||||||
|
}
|
||||||
|
if (!document.body.contains(elem[0])) {
|
||||||
|
throw new Error("Error rendering Bokeh model: element with id '" + element_id + "' must be under <body>");
|
||||||
|
}
|
||||||
|
if (elem.prop("tagName") === "SCRIPT") {
|
||||||
|
fill_render_item_from_script_tag(elem, item);
|
||||||
|
container = $('<div>', {
|
||||||
|
"class": BOKEH_ROOT
|
||||||
|
});
|
||||||
|
elem.replaceWith(container);
|
||||||
|
elem = container;
|
||||||
|
}
|
||||||
|
use_for_title = (item.use_for_title != null) && item.use_for_title;
|
||||||
|
promise = null;
|
||||||
|
if (item.modelid != null) {
|
||||||
|
if (item.docid != null) {
|
||||||
|
add_model_static(elem, item.modelid, docs[item.docid]);
|
||||||
|
} else if (item.sessionid != null) {
|
||||||
|
promise = add_model_from_session(elem, websocket_url, item.modelid, item.sessionid);
|
||||||
|
} else {
|
||||||
|
throw new Error("Error rendering Bokeh model " + item['modelid'] + " to element " + element_id + ": no document ID or session ID specified");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.docid != null) {
|
||||||
|
add_document_static(elem, docs[item.docid], use_for_title);
|
||||||
|
} else if (item.sessionid != null) {
|
||||||
|
promise = add_document_from_session(elem, websocket_url, item.sessionid, use_for_title);
|
||||||
|
} else {
|
||||||
|
throw new Error("Error rendering Bokeh document to element " + element_id + ": no document ID or session ID specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (promise !== null) {
|
||||||
|
results.push(promise.then(function(value) {
|
||||||
|
return console.log("Bokeh items were rendered successfully");
|
||||||
|
}, function(error) {
|
||||||
|
return console.log("Error rendering Bokeh items ", error);
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
embed_items: embed_items,
|
||||||
|
add_document_static: add_document_static,
|
||||||
|
add_document_standalone: add_document_standalone,
|
||||||
|
inject_css: inject_css,
|
||||||
|
inject_raw_css: inject_raw_css,
|
||||||
|
BOKEH_ROOT: BOKEH_ROOT
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
var Bokeh, _, logging;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Bokeh = {};
|
||||||
|
|
||||||
|
Bokeh.require = require;
|
||||||
|
|
||||||
|
Bokeh.version = require("./version");
|
||||||
|
|
||||||
|
Bokeh._ = require("underscore");
|
||||||
|
|
||||||
|
Bokeh.$ = require("jquery");
|
||||||
|
|
||||||
|
Bokeh.Backbone = require("backbone");
|
||||||
|
|
||||||
|
Bokeh.Backbone.$ = Bokeh.$;
|
||||||
|
|
||||||
|
logging = require("./core/logging");
|
||||||
|
|
||||||
|
Bokeh.logger = logging.logger;
|
||||||
|
|
||||||
|
Bokeh.set_log_level = logging.set_log_level;
|
||||||
|
|
||||||
|
Bokeh.index = require("./base").index;
|
||||||
|
|
||||||
|
Bokeh.embed = require("./embed");
|
||||||
|
|
||||||
|
Bokeh.safely = require("./safely");
|
||||||
|
|
||||||
|
Bokeh.Models = require("./base").Models;
|
||||||
|
|
||||||
|
Bokeh.Bokeh = Bokeh;
|
||||||
|
|
||||||
|
module.exports = Bokeh;
|
|
@ -0,0 +1,71 @@
|
||||||
|
var HasProps, Model, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
HasProps = require("./core/has_props");
|
||||||
|
|
||||||
|
p = require("./core/properties");
|
||||||
|
|
||||||
|
Model = (function(superClass) {
|
||||||
|
extend(Model, superClass);
|
||||||
|
|
||||||
|
function Model() {
|
||||||
|
return Model.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model.prototype.type = "Model";
|
||||||
|
|
||||||
|
Model.prototype._coords = [];
|
||||||
|
|
||||||
|
Model.coords = function(coords) {
|
||||||
|
var _coords, i, len, ref1, result, x, y;
|
||||||
|
_coords = this.prototype._coords.concat(coords);
|
||||||
|
this.prototype._coords = _coords;
|
||||||
|
result = {};
|
||||||
|
for (i = 0, len = coords.length; i < len; i++) {
|
||||||
|
ref1 = coords[i], x = ref1[0], y = ref1[1];
|
||||||
|
result[x] = [p.NumberSpec];
|
||||||
|
result[y] = [p.NumberSpec];
|
||||||
|
}
|
||||||
|
return this.define(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
Model.define({
|
||||||
|
tags: [p.Array, []],
|
||||||
|
name: [p.String]
|
||||||
|
});
|
||||||
|
|
||||||
|
Model.prototype.select = function(selector) {
|
||||||
|
if (selector.prototype instanceof Model) {
|
||||||
|
return this.references().filter(function(ref) {
|
||||||
|
return ref instanceof selector;
|
||||||
|
});
|
||||||
|
} else if (_.isString(selector)) {
|
||||||
|
return this.references().filter(function(ref) {
|
||||||
|
return ref.name === selector;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error("invalid selector");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Model.prototype.select_one = function(selector) {
|
||||||
|
var result;
|
||||||
|
result = this.select(selector);
|
||||||
|
switch (result.length) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
case 1:
|
||||||
|
return result[0];
|
||||||
|
default:
|
||||||
|
throw new Error("found more than one object matching given selector");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Model;
|
||||||
|
|
||||||
|
})(HasProps);
|
||||||
|
|
||||||
|
module.exports = Model;
|
|
@ -0,0 +1,72 @@
|
||||||
|
var Annotation, AnnotationView, Renderer, SidePanel, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
SidePanel = require("../../core/layout/side_panel");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Renderer = require("../renderers/renderer");
|
||||||
|
|
||||||
|
AnnotationView = (function(superClass) {
|
||||||
|
extend(AnnotationView, superClass);
|
||||||
|
|
||||||
|
function AnnotationView() {
|
||||||
|
return AnnotationView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationView.prototype._get_panel_offset = function() {
|
||||||
|
var x, y;
|
||||||
|
x = this.model.panel._left._value;
|
||||||
|
y = this.model.panel._bottom._value;
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: -y
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnotationView.prototype._get_size = function() {
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
return AnnotationView;
|
||||||
|
|
||||||
|
})(Renderer.View);
|
||||||
|
|
||||||
|
Annotation = (function(superClass) {
|
||||||
|
extend(Annotation, superClass);
|
||||||
|
|
||||||
|
function Annotation() {
|
||||||
|
return Annotation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Annotation.prototype.type = 'Annotation';
|
||||||
|
|
||||||
|
Annotation.prototype.default_view = AnnotationView;
|
||||||
|
|
||||||
|
Annotation.define({
|
||||||
|
plot: [p.Instance]
|
||||||
|
});
|
||||||
|
|
||||||
|
Annotation.override({
|
||||||
|
level: 'annotation'
|
||||||
|
});
|
||||||
|
|
||||||
|
Annotation.prototype.add_panel = function(side) {
|
||||||
|
this.panel = new SidePanel.Model({
|
||||||
|
side: side
|
||||||
|
});
|
||||||
|
this.panel.attach_document(this.document);
|
||||||
|
return this.level = 'overlay';
|
||||||
|
};
|
||||||
|
|
||||||
|
return Annotation;
|
||||||
|
|
||||||
|
})(Renderer.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Annotation,
|
||||||
|
View: AnnotationView
|
||||||
|
};
|
|
@ -0,0 +1,144 @@
|
||||||
|
var Annotation, Arrow, ArrowView, ColumnDataSource, OpenHead, _, atan2, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
OpenHead = require("./arrow_head").OpenHead;
|
||||||
|
|
||||||
|
ColumnDataSource = require("../sources/column_data_source");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
atan2 = require("../../core/util/math").atan2;
|
||||||
|
|
||||||
|
ArrowView = (function(superClass) {
|
||||||
|
extend(ArrowView, superClass);
|
||||||
|
|
||||||
|
function ArrowView() {
|
||||||
|
return ArrowView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowView.prototype.initialize = function(options) {
|
||||||
|
ArrowView.__super__.initialize.call(this, options);
|
||||||
|
if (this.mget('source') == null) {
|
||||||
|
this.mset('source', new ColumnDataSource.Model());
|
||||||
|
}
|
||||||
|
this.canvas = this.plot_model.get('canvas');
|
||||||
|
this.xmapper = this.plot_view.frame.get('x_mappers')[this.mget("x_range_name")];
|
||||||
|
this.ymapper = this.plot_view.frame.get('y_mappers')[this.mget("y_range_name")];
|
||||||
|
return this.set_data();
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype.bind_bokeh_events = function() {
|
||||||
|
this.listenTo(this.model, 'change', this.plot_view.request_render);
|
||||||
|
return this.listenTo(this.mget('source'), 'change', function() {
|
||||||
|
this.set_data();
|
||||||
|
return this.plot_view.request_render();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype.set_data = function() {
|
||||||
|
ArrowView.__super__.set_data.call(this, this.mget('source'));
|
||||||
|
return this.set_visuals(this.mget('source'));
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype._map_data = function() {
|
||||||
|
var end, start, x_name, y_name;
|
||||||
|
if (this.mget('start_units') === 'data') {
|
||||||
|
start = this.plot_view.map_to_screen(this._x_start, this._y_start, x_name = this.mget('x_range_name'), y_name = this.mget('y_range_name'));
|
||||||
|
} else {
|
||||||
|
start = [this.canvas.v_vx_to_sx(this._x_start), this.canvas.v_vy_to_sy(this._y_start)];
|
||||||
|
}
|
||||||
|
if (this.mget('end_units') === 'data') {
|
||||||
|
end = this.plot_view.map_to_screen(this._x_end, this._y_end, x_name = this.mget('x_range_name'), y_name = this.mget('y_range_name'));
|
||||||
|
} else {
|
||||||
|
end = [this.canvas.v_vx_to_sx(this._x_end), this.canvas.v_vy_to_sy(this._y_end)];
|
||||||
|
}
|
||||||
|
return [start, end];
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype.render = function() {
|
||||||
|
var ref;
|
||||||
|
ref = this._map_data(), this.start = ref[0], this.end = ref[1];
|
||||||
|
this._draw_arrow_body();
|
||||||
|
if (this.mget('end') != null) {
|
||||||
|
this._draw_arrow_head(this.mget('end'), this.start, this.end);
|
||||||
|
}
|
||||||
|
if (this.mget('start') != null) {
|
||||||
|
return this._draw_arrow_head(this.mget('start'), this.end, this.start);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype._draw_arrow_body = function() {
|
||||||
|
var ctx, i, j, ref;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
for (i = j = 0, ref = this._x_start.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(this.start[0][i], this.start[1][i]);
|
||||||
|
ctx.lineTo(this.end[0][i], this.end[1][i]);
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowView.prototype._draw_arrow_head = function(head, start, end) {
|
||||||
|
var angle, ctx, i, j, ref, results;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = this._x_start.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
angle = Math.PI / 2 + atan2([start[0][i], start[1][i]], [end[0][i], end[1][i]]);
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(end[0][i], end[1][i]);
|
||||||
|
ctx.rotate(angle);
|
||||||
|
head.render(ctx, i);
|
||||||
|
results.push(ctx.restore());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ArrowView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
Arrow = (function(superClass) {
|
||||||
|
extend(Arrow, superClass);
|
||||||
|
|
||||||
|
function Arrow() {
|
||||||
|
return Arrow.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrow.prototype.default_view = ArrowView;
|
||||||
|
|
||||||
|
Arrow.prototype.type = 'Arrow';
|
||||||
|
|
||||||
|
Arrow.mixins(['line']);
|
||||||
|
|
||||||
|
Arrow.define({
|
||||||
|
x_start: [p.NumberSpec],
|
||||||
|
y_start: [p.NumberSpec],
|
||||||
|
start_units: [p.String, 'data'],
|
||||||
|
start: [p.Instance, null],
|
||||||
|
x_end: [p.NumberSpec],
|
||||||
|
y_end: [p.NumberSpec],
|
||||||
|
end_units: [p.String, 'data'],
|
||||||
|
end: [p.Instance, new OpenHead.Model({})],
|
||||||
|
source: [p.Instance],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default']
|
||||||
|
});
|
||||||
|
|
||||||
|
return Arrow;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Arrow,
|
||||||
|
View: ArrowView
|
||||||
|
};
|
|
@ -0,0 +1,178 @@
|
||||||
|
var Annotation, ArrowHead, NormalHead, OpenHead, Renderer, VeeHead, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
Renderer = require("../renderers/renderer");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
ArrowHead = (function(superClass) {
|
||||||
|
extend(ArrowHead, superClass);
|
||||||
|
|
||||||
|
function ArrowHead() {
|
||||||
|
return ArrowHead.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowHead.prototype.type = 'ArrowHead';
|
||||||
|
|
||||||
|
ArrowHead.prototype.initialize = function(options) {
|
||||||
|
var j, len, name, prefix, ref, ref1, results, spec;
|
||||||
|
ArrowHead.__super__.initialize.call(this, options);
|
||||||
|
this.visuals = {};
|
||||||
|
ref = this.mixins;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||||||
|
spec = ref[j];
|
||||||
|
ref1 = spec.split(":"), name = ref1[0], prefix = ref1[1];
|
||||||
|
if (prefix == null) {
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
results.push(this.visuals[prefix + name] = new Renderer.Visuals[name]({
|
||||||
|
obj: this,
|
||||||
|
prefix: prefix
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrowHead.prototype.render = function(ctx, i) {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ArrowHead;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
OpenHead = (function(superClass) {
|
||||||
|
extend(OpenHead, superClass);
|
||||||
|
|
||||||
|
function OpenHead() {
|
||||||
|
return OpenHead.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenHead.prototype.type = 'OpenHead';
|
||||||
|
|
||||||
|
OpenHead.prototype.render = function(ctx, i) {
|
||||||
|
if (this.visuals["line"].doit) {
|
||||||
|
this.visuals["line"].set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.lineTo(-0.5 * this.get("size"), this.get("size"));
|
||||||
|
return ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenHead.mixins(['line']);
|
||||||
|
|
||||||
|
OpenHead.define({
|
||||||
|
size: [p.Number, 25]
|
||||||
|
});
|
||||||
|
|
||||||
|
return OpenHead;
|
||||||
|
|
||||||
|
})(ArrowHead);
|
||||||
|
|
||||||
|
NormalHead = (function(superClass) {
|
||||||
|
extend(NormalHead, superClass);
|
||||||
|
|
||||||
|
function NormalHead() {
|
||||||
|
return NormalHead.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalHead.prototype.type = 'NormalHead';
|
||||||
|
|
||||||
|
NormalHead.prototype.render = function(ctx, i) {
|
||||||
|
if (this.visuals["fill"].doit) {
|
||||||
|
this.visuals["fill"].set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.lineTo(-0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals["line"].doit) {
|
||||||
|
this.visuals["line"].set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.lineTo(-0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.closePath();
|
||||||
|
return ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NormalHead.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
NormalHead.define({
|
||||||
|
size: [p.Number, 25]
|
||||||
|
});
|
||||||
|
|
||||||
|
NormalHead.override({
|
||||||
|
fill_color: 'black'
|
||||||
|
});
|
||||||
|
|
||||||
|
return NormalHead;
|
||||||
|
|
||||||
|
})(ArrowHead);
|
||||||
|
|
||||||
|
VeeHead = (function(superClass) {
|
||||||
|
extend(VeeHead, superClass);
|
||||||
|
|
||||||
|
function VeeHead() {
|
||||||
|
return VeeHead.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
VeeHead.prototype.type = 'VeeHead';
|
||||||
|
|
||||||
|
VeeHead.prototype.render = function(ctx, i) {
|
||||||
|
if (this.visuals["fill"].doit) {
|
||||||
|
this.visuals["fill"].set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.lineTo(-0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0.5 * this.get("size"));
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals["line"].doit) {
|
||||||
|
this.visuals["line"].set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.lineTo(-0.5 * this.get("size"), this.get("size"));
|
||||||
|
ctx.lineTo(0, 0.5 * this.get("size"));
|
||||||
|
ctx.closePath();
|
||||||
|
return ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VeeHead.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
VeeHead.define({
|
||||||
|
size: [p.Number, 25]
|
||||||
|
});
|
||||||
|
|
||||||
|
VeeHead.override({
|
||||||
|
fill_color: 'black'
|
||||||
|
});
|
||||||
|
|
||||||
|
return VeeHead;
|
||||||
|
|
||||||
|
})(ArrowHead);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
OpenHead: {
|
||||||
|
Model: OpenHead
|
||||||
|
},
|
||||||
|
NormalHead: {
|
||||||
|
Model: NormalHead
|
||||||
|
},
|
||||||
|
VeeHead: {
|
||||||
|
Model: VeeHead
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,166 @@
|
||||||
|
var Annotation, BoxAnnotation, BoxAnnotationView, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
BoxAnnotationView = (function(superClass) {
|
||||||
|
extend(BoxAnnotationView, superClass);
|
||||||
|
|
||||||
|
function BoxAnnotationView() {
|
||||||
|
return BoxAnnotationView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype.initialize = function(options) {
|
||||||
|
BoxAnnotationView.__super__.initialize.call(this, options);
|
||||||
|
this.$el.appendTo(this.plot_view.$el.find('div.bk-canvas-overlays'));
|
||||||
|
this.$el.addClass('bk-shading');
|
||||||
|
return this.$el.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype.bind_bokeh_events = function() {
|
||||||
|
if (this.mget('render_mode') === 'css') {
|
||||||
|
this.listenTo(this.model, 'change', this.render);
|
||||||
|
return this.listenTo(this.model, 'data_update', this.render);
|
||||||
|
} else {
|
||||||
|
this.listenTo(this.model, 'change', this.plot_view.request_render);
|
||||||
|
return this.listenTo(this.model, 'data_update', this.plot_view.request_render);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype.render = function() {
|
||||||
|
var sbottom, sleft, sright, stop;
|
||||||
|
if ((this.mget('left') == null) && (this.mget('right') == null) && (this.mget('top') == null) && (this.mget('bottom') == null)) {
|
||||||
|
this.$el.hide();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.frame = this.plot_model.get('frame');
|
||||||
|
this.canvas = this.plot_model.get('canvas');
|
||||||
|
this.xmapper = this.plot_view.frame.get('x_mappers')[this.mget("x_range_name")];
|
||||||
|
this.ymapper = this.plot_view.frame.get('y_mappers')[this.mget("y_range_name")];
|
||||||
|
sleft = this.canvas.vx_to_sx(this._calc_dim('left', this.xmapper, this.frame.get('h_range').get('start')));
|
||||||
|
sright = this.canvas.vx_to_sx(this._calc_dim('right', this.xmapper, this.frame.get('h_range').get('end')));
|
||||||
|
sbottom = this.canvas.vy_to_sy(this._calc_dim('bottom', this.ymapper, this.frame.get('v_range').get('start')));
|
||||||
|
stop = this.canvas.vy_to_sy(this._calc_dim('top', this.ymapper, this.frame.get('v_range').get('end')));
|
||||||
|
if (this.mget('render_mode') === 'css') {
|
||||||
|
return this._css_box(sleft, sright, sbottom, stop);
|
||||||
|
} else {
|
||||||
|
return this._canvas_box(sleft, sright, sbottom, stop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype._css_box = function(sleft, sright, sbottom, stop) {
|
||||||
|
var ba, bc, lc, ld, lw, sh, style, sw;
|
||||||
|
sw = Math.abs(sright - sleft);
|
||||||
|
sh = Math.abs(sbottom - stop);
|
||||||
|
lw = this.mget("line_width").value;
|
||||||
|
lc = this.mget("line_color").value;
|
||||||
|
bc = this.mget("fill_color").value;
|
||||||
|
ba = this.mget("fill_alpha").value;
|
||||||
|
style = "left:" + sleft + "px; width:" + sw + "px; top:" + stop + "px; height:" + sh + "px; border-width:" + lw + "px; border-color:" + lc + "; background-color:" + bc + "; opacity:" + ba + ";";
|
||||||
|
ld = this.mget("line_dash");
|
||||||
|
if (_.isArray(ld)) {
|
||||||
|
if (ld.length < 2) {
|
||||||
|
ld = "solid";
|
||||||
|
} else {
|
||||||
|
ld = "dashed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.isString(ld)) {
|
||||||
|
style += " border-style:" + ld + ";";
|
||||||
|
}
|
||||||
|
this.$el.attr('style', style);
|
||||||
|
return this.$el.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype._canvas_box = function(sleft, sright, sbottom, stop) {
|
||||||
|
var ctx;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(sleft, stop, sright - sleft, sbottom - stop);
|
||||||
|
this.visuals.fill.set_value(ctx);
|
||||||
|
ctx.fill();
|
||||||
|
this.visuals.line.set_value(ctx);
|
||||||
|
ctx.stroke();
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxAnnotationView.prototype._calc_dim = function(dim, mapper, frame_extrema) {
|
||||||
|
var vdim;
|
||||||
|
if (this.mget(dim) != null) {
|
||||||
|
if (this.mget(dim + '_units') === 'data') {
|
||||||
|
vdim = mapper.map_to_target(this.mget(dim));
|
||||||
|
} else {
|
||||||
|
vdim = this.mget(dim);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vdim = frame_extrema;
|
||||||
|
}
|
||||||
|
return vdim;
|
||||||
|
};
|
||||||
|
|
||||||
|
return BoxAnnotationView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
BoxAnnotation = (function(superClass) {
|
||||||
|
extend(BoxAnnotation, superClass);
|
||||||
|
|
||||||
|
function BoxAnnotation() {
|
||||||
|
return BoxAnnotation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxAnnotation.prototype.default_view = BoxAnnotationView;
|
||||||
|
|
||||||
|
BoxAnnotation.prototype.type = 'BoxAnnotation';
|
||||||
|
|
||||||
|
BoxAnnotation.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
BoxAnnotation.define({
|
||||||
|
render_mode: [p.RenderMode, 'canvas'],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default'],
|
||||||
|
top: [p.Number, null],
|
||||||
|
top_units: [p.SpatialUnits, 'data'],
|
||||||
|
bottom: [p.Number, null],
|
||||||
|
bottom_units: [p.SpatialUnits, 'data'],
|
||||||
|
left: [p.Number, null],
|
||||||
|
left_units: [p.SpatialUnits, 'data'],
|
||||||
|
right: [p.Number, null],
|
||||||
|
right_units: [p.SpatialUnits, 'data']
|
||||||
|
});
|
||||||
|
|
||||||
|
BoxAnnotation.override({
|
||||||
|
fill_color: '#fff9ba',
|
||||||
|
fill_alpha: 0.4,
|
||||||
|
line_color: '#cccccc',
|
||||||
|
line_alpha: 0.3
|
||||||
|
});
|
||||||
|
|
||||||
|
BoxAnnotation.prototype.update = function(arg) {
|
||||||
|
var bottom, left, right, top;
|
||||||
|
left = arg.left, right = arg.right, top = arg.top, bottom = arg.bottom;
|
||||||
|
this.set({
|
||||||
|
left: left,
|
||||||
|
right: right,
|
||||||
|
top: top,
|
||||||
|
bottom: bottom
|
||||||
|
}, {
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
|
return this.trigger('data_update');
|
||||||
|
};
|
||||||
|
|
||||||
|
return BoxAnnotation;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: BoxAnnotation,
|
||||||
|
View: BoxAnnotationView
|
||||||
|
};
|
|
@ -0,0 +1,638 @@
|
||||||
|
var Annotation, BasicTickFormatter, BasicTicker, ColorBar, ColorBarView, LONG_DIM_MAX_SCALAR, LONG_DIM_MIN_SCALAR, LinearColorMapper, LinearMapper, LogMapper, Range1d, SHORT_DIM, _, p, text_util,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
BasicTicker = require("../tickers/basic_ticker");
|
||||||
|
|
||||||
|
BasicTickFormatter = require("../formatters/basic_tick_formatter");
|
||||||
|
|
||||||
|
LinearColorMapper = require("../mappers/linear_color_mapper");
|
||||||
|
|
||||||
|
LinearMapper = require("../mappers/linear_mapper");
|
||||||
|
|
||||||
|
LogMapper = require("../mappers/log_mapper");
|
||||||
|
|
||||||
|
Range1d = require("../ranges/range1d");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
text_util = require("../../core/util/text");
|
||||||
|
|
||||||
|
SHORT_DIM = 25;
|
||||||
|
|
||||||
|
LONG_DIM_MIN_SCALAR = 0.3;
|
||||||
|
|
||||||
|
LONG_DIM_MAX_SCALAR = 0.8;
|
||||||
|
|
||||||
|
ColorBarView = (function(superClass) {
|
||||||
|
extend(ColorBarView, superClass);
|
||||||
|
|
||||||
|
function ColorBarView() {
|
||||||
|
return ColorBarView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorBarView.prototype.initialize = function(options) {
|
||||||
|
ColorBarView.__super__.initialize.call(this, options);
|
||||||
|
return this._set_canvas_image();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype.bind_bokeh_events = function() {
|
||||||
|
this.listenTo(this.model, 'change:visible', this.plot_view.request_render);
|
||||||
|
this.listenTo(this.model.ticker, 'change', this.plot_view.request_render);
|
||||||
|
this.listenTo(this.model.formatter, 'change', this.plot_view.request_render);
|
||||||
|
return this.listenTo(this.model.color_mapper, 'change', function() {
|
||||||
|
this._set_canvas_image();
|
||||||
|
return this.plot_view.request_render();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._get_panel_offset = function() {
|
||||||
|
var x, y;
|
||||||
|
x = this.model.panel._left._value;
|
||||||
|
y = this.model.panel._top._value;
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: -y
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._get_size = function() {
|
||||||
|
var bbox, side;
|
||||||
|
bbox = this.compute_legend_dimensions();
|
||||||
|
side = this.model.panel.side;
|
||||||
|
if (side === 'above' || side === 'below') {
|
||||||
|
return bbox.height;
|
||||||
|
}
|
||||||
|
if (side === 'left' || side === 'right') {
|
||||||
|
return bbox.width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._set_canvas_image = function() {
|
||||||
|
var buf, buf8, canvas, cmap, h, image_ctx, image_data, k, palette, ref, ref1, ref2, ref3, results, w;
|
||||||
|
palette = this.model.color_mapper.palette;
|
||||||
|
if (this.model.orientation === 'vertical') {
|
||||||
|
palette = palette.slice(0).reverse();
|
||||||
|
}
|
||||||
|
switch (this.model.orientation) {
|
||||||
|
case "vertical":
|
||||||
|
ref = [1, palette.length], w = ref[0], h = ref[1];
|
||||||
|
break;
|
||||||
|
case "horizontal":
|
||||||
|
ref1 = [palette.length, 1], w = ref1[0], h = ref1[1];
|
||||||
|
}
|
||||||
|
canvas = document.createElement('canvas');
|
||||||
|
ref2 = [w, h], canvas.width = ref2[0], canvas.height = ref2[1];
|
||||||
|
image_ctx = canvas.getContext('2d');
|
||||||
|
image_data = image_ctx.getImageData(0, 0, w, h);
|
||||||
|
cmap = new LinearColorMapper.Model({
|
||||||
|
palette: palette
|
||||||
|
});
|
||||||
|
buf = cmap.v_map_screen((function() {
|
||||||
|
results = [];
|
||||||
|
for (var k = 0, ref3 = palette.length; 0 <= ref3 ? k < ref3 : k > ref3; 0 <= ref3 ? k++ : k--){ results.push(k); }
|
||||||
|
return results;
|
||||||
|
}).apply(this));
|
||||||
|
buf8 = new Uint8ClampedArray(buf);
|
||||||
|
image_data.data.set(buf8);
|
||||||
|
image_ctx.putImageData(image_data, 0, 0);
|
||||||
|
return this.image = canvas;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype.compute_legend_dimensions = function() {
|
||||||
|
var image_dimensions, image_height, image_width, label_extent, legend_height, legend_width, padding, ref, tick_extent, title_extent;
|
||||||
|
image_dimensions = this.model._computed_image_dimensions();
|
||||||
|
ref = [image_dimensions.height, image_dimensions.width], image_height = ref[0], image_width = ref[1];
|
||||||
|
label_extent = this._get_label_extent();
|
||||||
|
title_extent = this.model._title_extent();
|
||||||
|
tick_extent = this.model._tick_extent();
|
||||||
|
padding = this.model.padding;
|
||||||
|
switch (this.model.orientation) {
|
||||||
|
case "vertical":
|
||||||
|
legend_height = image_height + title_extent + padding * 2;
|
||||||
|
legend_width = image_width + tick_extent + label_extent + padding * 2;
|
||||||
|
break;
|
||||||
|
case "horizontal":
|
||||||
|
legend_height = image_height + title_extent + tick_extent + label_extent + padding * 2;
|
||||||
|
legend_width = image_width + padding * 2;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
height: legend_height,
|
||||||
|
width: legend_width
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype.compute_legend_location = function() {
|
||||||
|
var h_range, legend_dimensions, legend_height, legend_margin, legend_width, location, ref, sx, sy, v_range, x, y;
|
||||||
|
legend_dimensions = this.compute_legend_dimensions();
|
||||||
|
ref = [legend_dimensions.height, legend_dimensions.width], legend_height = ref[0], legend_width = ref[1];
|
||||||
|
legend_margin = this.model.margin;
|
||||||
|
location = this.model.location;
|
||||||
|
h_range = this.plot_view.frame.get('h_range');
|
||||||
|
v_range = this.plot_view.frame.get('v_range');
|
||||||
|
if (_.isString(location)) {
|
||||||
|
switch (location) {
|
||||||
|
case 'top_left':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'top_center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'top_right':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'right_center':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
break;
|
||||||
|
case 'bottom_right':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'bottom_center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'bottom_left':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'left_center':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
}
|
||||||
|
} else if (_.isArray(location) && location.length === 2) {
|
||||||
|
x = location[0], y = location[1];
|
||||||
|
}
|
||||||
|
sx = this.plot_view.canvas.vx_to_sx(x);
|
||||||
|
sy = this.plot_view.canvas.vy_to_sy(y);
|
||||||
|
return {
|
||||||
|
sx: sx,
|
||||||
|
sy: sy
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype.render = function() {
|
||||||
|
var ctx, frame_offset, image_offset, location, panel_offset;
|
||||||
|
if (this.model.visible === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
if (this.model.panel != null) {
|
||||||
|
panel_offset = this._get_panel_offset();
|
||||||
|
ctx.translate(panel_offset.x, panel_offset.y);
|
||||||
|
frame_offset = this._get_frame_offset();
|
||||||
|
ctx.translate(frame_offset.x, frame_offset.y);
|
||||||
|
}
|
||||||
|
location = this.compute_legend_location();
|
||||||
|
ctx.translate(location.sx, location.sy);
|
||||||
|
this._draw_bbox(ctx);
|
||||||
|
image_offset = this._get_image_offset();
|
||||||
|
ctx.translate(image_offset.x, image_offset.y);
|
||||||
|
this._draw_image(ctx);
|
||||||
|
if ((this.model.color_mapper.low != null) && (this.model.color_mapper.high != null)) {
|
||||||
|
this._draw_major_ticks(ctx);
|
||||||
|
this._draw_minor_ticks(ctx);
|
||||||
|
this._draw_major_labels(ctx);
|
||||||
|
}
|
||||||
|
if (this.model.title) {
|
||||||
|
this._draw_title(ctx);
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_bbox = function(ctx) {
|
||||||
|
var bbox;
|
||||||
|
bbox = this.compute_legend_dimensions();
|
||||||
|
ctx.save();
|
||||||
|
if (this.visuals.background_fill.doit) {
|
||||||
|
this.visuals.background_fill.set_value(ctx);
|
||||||
|
ctx.fillRect(0, 0, bbox.width, bbox.height);
|
||||||
|
}
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
this.visuals.border_line.set_value(ctx);
|
||||||
|
ctx.strokeRect(0, 0, bbox.width, bbox.height);
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_image = function(ctx) {
|
||||||
|
var image;
|
||||||
|
image = this.model._computed_image_dimensions();
|
||||||
|
ctx.save();
|
||||||
|
ctx.setImageSmoothingEnabled(false);
|
||||||
|
ctx.globalAlpha = this.model.scale_alpha;
|
||||||
|
ctx.drawImage(this.image, 0, 0, image.width, image.height);
|
||||||
|
if (this.visuals.bar_line.doit) {
|
||||||
|
this.visuals.bar_line.set_value(ctx);
|
||||||
|
ctx.strokeRect(0, 0, image.width, image.height);
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_major_ticks = function(ctx) {
|
||||||
|
var i, image, k, nx, ny, ref, ref1, ref2, ref3, sx, sy, tin, tout, x_offset, y_offset;
|
||||||
|
if (!this.visuals.major_tick_line.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ref = this.model._normals(), nx = ref[0], ny = ref[1];
|
||||||
|
image = this.model._computed_image_dimensions();
|
||||||
|
ref1 = [image.width * nx, image.height * ny], x_offset = ref1[0], y_offset = ref1[1];
|
||||||
|
ref2 = this.model._tick_coordinates().major, sx = ref2[0], sy = ref2[1];
|
||||||
|
tin = this.model.major_tick_in;
|
||||||
|
tout = this.model.major_tick_out;
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x_offset, y_offset);
|
||||||
|
this.visuals.major_tick_line.set_value(ctx);
|
||||||
|
for (i = k = 0, ref3 = sx.length; 0 <= ref3 ? k < ref3 : k > ref3; i = 0 <= ref3 ? ++k : --k) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(Math.round(sx[i] + nx * tout), Math.round(sy[i] + ny * tout));
|
||||||
|
ctx.lineTo(Math.round(sx[i] - nx * tin), Math.round(sy[i] - ny * tin));
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_minor_ticks = function(ctx) {
|
||||||
|
var i, image, k, nx, ny, ref, ref1, ref2, ref3, sx, sy, tin, tout, x_offset, y_offset;
|
||||||
|
if (!this.visuals.minor_tick_line.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ref = this.model._normals(), nx = ref[0], ny = ref[1];
|
||||||
|
image = this.model._computed_image_dimensions();
|
||||||
|
ref1 = [image.width * nx, image.height * ny], x_offset = ref1[0], y_offset = ref1[1];
|
||||||
|
ref2 = this.model._tick_coordinates().minor, sx = ref2[0], sy = ref2[1];
|
||||||
|
tin = this.model.minor_tick_in;
|
||||||
|
tout = this.model.minor_tick_out;
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x_offset, y_offset);
|
||||||
|
this.visuals.minor_tick_line.set_value(ctx);
|
||||||
|
for (i = k = 0, ref3 = sx.length; 0 <= ref3 ? k < ref3 : k > ref3; i = 0 <= ref3 ? ++k : --k) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(Math.round(sx[i] + nx * tout), Math.round(sy[i] + ny * tout));
|
||||||
|
ctx.lineTo(Math.round(sx[i] - nx * tin), Math.round(sy[i] - ny * tin));
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_major_labels = function(ctx) {
|
||||||
|
var formatted_labels, i, image, k, labels, nx, ny, ref, ref1, ref2, ref3, ref4, standoff, sx, sy, x_offset, x_standoff, y_offset, y_standoff;
|
||||||
|
if (!this.visuals.major_label_text.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ref = this.model._normals(), nx = ref[0], ny = ref[1];
|
||||||
|
image = this.model._computed_image_dimensions();
|
||||||
|
ref1 = [image.width * nx, image.height * ny], x_offset = ref1[0], y_offset = ref1[1];
|
||||||
|
standoff = this.model.label_standoff + this.model._tick_extent();
|
||||||
|
ref2 = [standoff * nx, standoff * ny], x_standoff = ref2[0], y_standoff = ref2[1];
|
||||||
|
ref3 = this.model._tick_coordinates().major, sx = ref3[0], sy = ref3[1];
|
||||||
|
labels = this.model._tick_coordinates().major_labels;
|
||||||
|
formatted_labels = this.mget('formatter').doFormat(labels);
|
||||||
|
this.visuals.major_label_text.set_value(ctx);
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x_offset + x_standoff, y_offset + y_standoff);
|
||||||
|
for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) {
|
||||||
|
ctx.fillText(formatted_labels[i], Math.round(sx[i] + nx * this.model.label_standoff), Math.round(sy[i] + ny * this.model.label_standoff));
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._draw_title = function(ctx) {
|
||||||
|
if (!this.visuals.title_text.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.save();
|
||||||
|
this.visuals.title_text.set_value(ctx);
|
||||||
|
ctx.fillText(this.model.title, 0, -this.model.title_standoff);
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._get_label_extent = function() {
|
||||||
|
var ctx, formatted_labels, label, label_extent;
|
||||||
|
if ((this.model.color_mapper.low != null) && (this.model.color_mapper.high != null)) {
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
this.visuals.major_label_text.set_value(ctx);
|
||||||
|
switch (this.model.orientation) {
|
||||||
|
case "vertical":
|
||||||
|
formatted_labels = this.model.formatter.doFormat(this.model._tick_coordinates().major_labels);
|
||||||
|
label_extent = _.max((function() {
|
||||||
|
var k, len, results;
|
||||||
|
results = [];
|
||||||
|
for (k = 0, len = formatted_labels.length; k < len; k++) {
|
||||||
|
label = formatted_labels[k];
|
||||||
|
results.push(ctx.measureText(label.toString()).width);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})());
|
||||||
|
break;
|
||||||
|
case "horizontal":
|
||||||
|
label_extent = text_util.get_text_height(this.visuals.major_label_text.font_value()).height;
|
||||||
|
}
|
||||||
|
label_extent += this.model.label_standoff;
|
||||||
|
ctx.restore();
|
||||||
|
} else {
|
||||||
|
label_extent = 0;
|
||||||
|
}
|
||||||
|
return label_extent;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._get_frame_offset = function() {
|
||||||
|
var frame, panel, ref, xoff, yoff;
|
||||||
|
ref = [0, 0], xoff = ref[0], yoff = ref[1];
|
||||||
|
panel = this.model.panel;
|
||||||
|
frame = this.plot_view.frame;
|
||||||
|
switch (panel.side) {
|
||||||
|
case "left":
|
||||||
|
case "right":
|
||||||
|
yoff = Math.abs(panel.get("top") - frame.get("top"));
|
||||||
|
break;
|
||||||
|
case "above":
|
||||||
|
case "below":
|
||||||
|
xoff = Math.abs(frame.get("left"));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: xoff,
|
||||||
|
y: yoff
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBarView.prototype._get_image_offset = function() {
|
||||||
|
var x, y;
|
||||||
|
x = this.model.padding;
|
||||||
|
y = this.model.padding + this.model._title_extent();
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: y
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ColorBarView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
ColorBar = (function(superClass) {
|
||||||
|
extend(ColorBar, superClass);
|
||||||
|
|
||||||
|
function ColorBar() {
|
||||||
|
return ColorBar.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorBar.prototype.default_view = ColorBarView;
|
||||||
|
|
||||||
|
ColorBar.prototype.type = 'ColorBar';
|
||||||
|
|
||||||
|
ColorBar.mixins(['text:major_label_', 'text:title_', 'line:major_tick_', 'line:minor_tick_', 'line:border_', 'line:bar_', 'fill:background_']);
|
||||||
|
|
||||||
|
ColorBar.define({
|
||||||
|
location: [p.Any, 'top_right'],
|
||||||
|
orientation: [p.Orientation, 'vertical'],
|
||||||
|
title: [p.String],
|
||||||
|
title_standoff: [p.Number, 2],
|
||||||
|
height: [p.Any, 'auto'],
|
||||||
|
width: [p.Any, 'auto'],
|
||||||
|
scale_alpha: [p.Number, 1.0],
|
||||||
|
ticker: [
|
||||||
|
p.Instance, function() {
|
||||||
|
return new BasicTicker.Model();
|
||||||
|
}
|
||||||
|
],
|
||||||
|
formatter: [
|
||||||
|
p.Instance, function() {
|
||||||
|
return new BasicTickFormatter.Model();
|
||||||
|
}
|
||||||
|
],
|
||||||
|
color_mapper: [p.Instance],
|
||||||
|
label_standoff: [p.Number, 5],
|
||||||
|
margin: [p.Number, 30],
|
||||||
|
padding: [p.Number, 10],
|
||||||
|
major_tick_in: [p.Number, 5],
|
||||||
|
major_tick_out: [p.Number, 0],
|
||||||
|
minor_tick_in: [p.Number, 0],
|
||||||
|
minor_tick_out: [p.Number, 0]
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorBar.override({
|
||||||
|
background_fill_color: "#ffffff",
|
||||||
|
background_fill_alpha: 0.95,
|
||||||
|
bar_line_color: null,
|
||||||
|
border_line_color: null,
|
||||||
|
major_label_text_align: "center",
|
||||||
|
major_label_text_baseline: "middle",
|
||||||
|
major_label_text_font_size: "8pt",
|
||||||
|
major_tick_line_color: "#ffffff",
|
||||||
|
minor_tick_line_color: null,
|
||||||
|
title_text_font_size: "10pt",
|
||||||
|
title_text_font_style: "italic"
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorBar.prototype.initialize = function(attrs, options) {
|
||||||
|
return ColorBar.__super__.initialize.call(this, attrs, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._normals = function() {
|
||||||
|
var i, j, ref, ref1;
|
||||||
|
if (this.orientation === 'vertical') {
|
||||||
|
ref = [1, 0], i = ref[0], j = ref[1];
|
||||||
|
} else {
|
||||||
|
ref1 = [0, 1], i = ref1[0], j = ref1[1];
|
||||||
|
}
|
||||||
|
return [i, j];
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._title_extent = function() {
|
||||||
|
var font_value, title_extent;
|
||||||
|
font_value = this.title_text_font + " " + this.title_text_font_size + " " + this.title_text_font_style;
|
||||||
|
title_extent = this.title ? text_util.get_text_height(font_value).height + this.title_standoff : 0;
|
||||||
|
return title_extent;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._tick_extent = function() {
|
||||||
|
var tick_extent;
|
||||||
|
if ((this.color_mapper.low != null) && (this.color_mapper.high != null)) {
|
||||||
|
tick_extent = _.max([this.major_tick_out, this.minor_tick_out]);
|
||||||
|
} else {
|
||||||
|
tick_extent = 0;
|
||||||
|
}
|
||||||
|
return tick_extent;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._computed_image_dimensions = function() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Heuristics to determine ColorBar image dimensions if set to "auto"
|
||||||
|
|
||||||
|
Note: Returns the height/width values for the ColorBar's scale image, not
|
||||||
|
the dimensions of the entire ColorBar.
|
||||||
|
|
||||||
|
If the short dimension (the width of a vertical bar or height of a
|
||||||
|
horizontal bar) is set to "auto", the resulting dimension will be set to
|
||||||
|
25 px.
|
||||||
|
|
||||||
|
For a ColorBar in a side panel with the long dimension (the height of a
|
||||||
|
vertical bar or width of a horizontal bar) set to "auto", the
|
||||||
|
resulting dimension will be as long as the adjacent frame edge, so that the
|
||||||
|
bar "fits" to the plot.
|
||||||
|
|
||||||
|
For a ColorBar in the plot frame with the long dimension set to "auto", the
|
||||||
|
resulting dimension will be the greater of:
|
||||||
|
* The length of the color palette * 25px
|
||||||
|
* The parallel frame dimension * 0.30
|
||||||
|
(i.e the frame height for a vertical ColorBar)
|
||||||
|
But not greater than:
|
||||||
|
* The parallel frame dimension * 0.80
|
||||||
|
*/
|
||||||
|
var frame_height, frame_width, height, title_extent, width;
|
||||||
|
frame_height = this.plot.plot_canvas.frame.get('height');
|
||||||
|
frame_width = this.plot.plot_canvas.frame.get('width');
|
||||||
|
title_extent = this._title_extent();
|
||||||
|
switch (this.orientation) {
|
||||||
|
case "vertical":
|
||||||
|
if (this.height === 'auto') {
|
||||||
|
if (this.panel != null) {
|
||||||
|
height = frame_height - 2 * this.padding - title_extent;
|
||||||
|
} else {
|
||||||
|
height = _.max([this.color_mapper.palette.length * SHORT_DIM, frame_height * LONG_DIM_MIN_SCALAR]);
|
||||||
|
height = _.min([height, frame_height * LONG_DIM_MAX_SCALAR - 2 * this.padding - title_extent]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
height = this.height;
|
||||||
|
}
|
||||||
|
width = this.width === 'auto' ? SHORT_DIM : this.width;
|
||||||
|
break;
|
||||||
|
case "horizontal":
|
||||||
|
height = this.height === 'auto' ? SHORT_DIM : this.height;
|
||||||
|
if (this.width === 'auto') {
|
||||||
|
if (this.panel != null) {
|
||||||
|
width = frame_width - 2 * this.padding;
|
||||||
|
} else {
|
||||||
|
width = _.max([this.color_mapper.palette.length * SHORT_DIM, frame_width * LONG_DIM_MIN_SCALAR]);
|
||||||
|
width = _.min([width, frame_width * LONG_DIM_MAX_SCALAR - 2 * this.padding]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
width = this.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"height": height,
|
||||||
|
"width": width
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._tick_coordinate_mapper = function(scale_length) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates and returns a mapper instance that maps the `color_mapper` range
|
||||||
|
(low to high) to a screen space range equal to the length of the ColorBar's
|
||||||
|
scale image. The mapper is used to calculate the tick coordinates in screen
|
||||||
|
coordinates for plotting purposes.
|
||||||
|
|
||||||
|
Note: the type of color_mapper has to match the type of mapper (i.e.
|
||||||
|
a LinearColorMapper will require a corresponding LinearMapper instance).
|
||||||
|
*/
|
||||||
|
var mapper, mapping;
|
||||||
|
mapping = {
|
||||||
|
'source_range': new Range1d.Model({
|
||||||
|
start: this.color_mapper.low,
|
||||||
|
end: this.color_mapper.high
|
||||||
|
}),
|
||||||
|
'target_range': new Range1d.Model({
|
||||||
|
start: 0,
|
||||||
|
end: scale_length
|
||||||
|
})
|
||||||
|
};
|
||||||
|
switch (this.color_mapper.type) {
|
||||||
|
case "LinearColorMapper":
|
||||||
|
mapper = new LinearMapper.Model(mapping);
|
||||||
|
break;
|
||||||
|
case "LogColorMapper":
|
||||||
|
mapper = new LogMapper.Model(mapping);
|
||||||
|
}
|
||||||
|
return mapper;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorBar.prototype._tick_coordinates = function() {
|
||||||
|
var coord, end, i, ii, image_dimensions, j, k, l, major_coords, major_labels, majors, mapper, minor_coords, minors, ref, ref1, ref2, ref3, scale_length, start, ticks;
|
||||||
|
image_dimensions = this._computed_image_dimensions();
|
||||||
|
switch (this.orientation) {
|
||||||
|
case "vertical":
|
||||||
|
scale_length = image_dimensions.height;
|
||||||
|
break;
|
||||||
|
case "horizontal":
|
||||||
|
scale_length = image_dimensions.width;
|
||||||
|
}
|
||||||
|
mapper = this._tick_coordinate_mapper(scale_length);
|
||||||
|
ref = this._normals(), i = ref[0], j = ref[1];
|
||||||
|
ref1 = [this.color_mapper.low, this.color_mapper.high], start = ref1[0], end = ref1[1];
|
||||||
|
ticks = this.ticker.get_ticks(start, end, null, this.ticker.desired_num_ticks);
|
||||||
|
majors = ticks.major;
|
||||||
|
minors = ticks.minor;
|
||||||
|
major_coords = [[], []];
|
||||||
|
minor_coords = [[], []];
|
||||||
|
for (ii = k = 0, ref2 = majors.length; 0 <= ref2 ? k < ref2 : k > ref2; ii = 0 <= ref2 ? ++k : --k) {
|
||||||
|
if (majors[ii] < start || majors[ii] > end) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
major_coords[i].push(majors[ii]);
|
||||||
|
major_coords[j].push(0);
|
||||||
|
}
|
||||||
|
for (ii = l = 0, ref3 = minors.length; 0 <= ref3 ? l < ref3 : l > ref3; ii = 0 <= ref3 ? ++l : --l) {
|
||||||
|
if (minors[ii] < start || minors[ii] > end) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
minor_coords[i].push(minors[ii]);
|
||||||
|
minor_coords[j].push(0);
|
||||||
|
}
|
||||||
|
major_labels = major_coords[i].slice(0);
|
||||||
|
major_coords[i] = mapper.v_map_to_target(major_coords[i]);
|
||||||
|
minor_coords[i] = mapper.v_map_to_target(minor_coords[i]);
|
||||||
|
if (this.orientation === 'vertical') {
|
||||||
|
major_coords[i] = new Float64Array((function() {
|
||||||
|
var len, m, ref4, results;
|
||||||
|
ref4 = major_coords[i];
|
||||||
|
results = [];
|
||||||
|
for (m = 0, len = ref4.length; m < len; m++) {
|
||||||
|
coord = ref4[m];
|
||||||
|
results.push(scale_length - coord);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})());
|
||||||
|
minor_coords[i] = new Float64Array((function() {
|
||||||
|
var len, m, ref4, results;
|
||||||
|
ref4 = minor_coords[i];
|
||||||
|
results = [];
|
||||||
|
for (m = 0, len = ref4.length; m < len; m++) {
|
||||||
|
coord = ref4[m];
|
||||||
|
results.push(scale_length - coord);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})());
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"major": major_coords,
|
||||||
|
"minor": minor_coords,
|
||||||
|
"major_labels": major_labels
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ColorBar;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: ColorBar,
|
||||||
|
View: ColorBarView
|
||||||
|
};
|
|
@ -0,0 +1,124 @@
|
||||||
|
var Label, LabelView, TextAnnotation, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
TextAnnotation = require("./text_annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
LabelView = (function(superClass) {
|
||||||
|
extend(LabelView, superClass);
|
||||||
|
|
||||||
|
function LabelView() {
|
||||||
|
return LabelView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelView.prototype.initialize = function(options) {
|
||||||
|
var name, prop, ref, results;
|
||||||
|
LabelView.__super__.initialize.call(this, options);
|
||||||
|
this.canvas = this.plot_model.get('canvas');
|
||||||
|
this.xmapper = this.plot_view.frame.get('x_mappers')[this.mget("x_range_name")];
|
||||||
|
this.ymapper = this.plot_view.frame.get('y_mappers')[this.mget("y_range_name")];
|
||||||
|
ref = this.visuals;
|
||||||
|
results = [];
|
||||||
|
for (name in ref) {
|
||||||
|
prop = ref[name];
|
||||||
|
results.push(prop.warm_cache(null));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelView.prototype._get_size = function() {
|
||||||
|
var ctx, height, side, width;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
side = this.model.panel.side;
|
||||||
|
if (side === "above" || side === "below") {
|
||||||
|
height = ctx.measureText(this.mget('text')).ascent;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
if (side === 'left' || side === 'right') {
|
||||||
|
width = ctx.measureText(this.mget('text')).width;
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelView.prototype.render = function() {
|
||||||
|
var angle, ctx, panel_offset, sx, sy, vx, vy;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
switch (this.mget('angle_units')) {
|
||||||
|
case "rad":
|
||||||
|
angle = -1 * this.mget('angle');
|
||||||
|
break;
|
||||||
|
case "deg":
|
||||||
|
angle = -1 * this.mget('angle') * Math.PI / 180.0;
|
||||||
|
}
|
||||||
|
if (this.mget('x_units') === "data") {
|
||||||
|
vx = this.xmapper.map_to_target(this.mget('x'));
|
||||||
|
} else {
|
||||||
|
vx = this.mget('x');
|
||||||
|
}
|
||||||
|
sx = this.canvas.vx_to_sx(vx);
|
||||||
|
if (this.mget('y_units') === "data") {
|
||||||
|
vy = this.ymapper.map_to_target(this.mget('y'));
|
||||||
|
} else {
|
||||||
|
vy = this.mget('y');
|
||||||
|
}
|
||||||
|
sy = this.canvas.vy_to_sy(vy);
|
||||||
|
if (this.model.panel != null) {
|
||||||
|
panel_offset = this._get_panel_offset();
|
||||||
|
sx += panel_offset.x;
|
||||||
|
sy += panel_offset.y;
|
||||||
|
}
|
||||||
|
if (this.mget('render_mode') === 'canvas') {
|
||||||
|
return this._canvas_text(ctx, this.mget('text'), sx + this.mget('x_offset'), sy - this.mget('y_offset'), angle);
|
||||||
|
} else {
|
||||||
|
return this._css_text(ctx, this.mget('text'), sx + this.mget('x_offset'), sy - this.mget('y_offset'), angle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return LabelView;
|
||||||
|
|
||||||
|
})(TextAnnotation.View);
|
||||||
|
|
||||||
|
Label = (function(superClass) {
|
||||||
|
extend(Label, superClass);
|
||||||
|
|
||||||
|
function Label() {
|
||||||
|
return Label.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Label.prototype.default_view = LabelView;
|
||||||
|
|
||||||
|
Label.prototype.type = 'Label';
|
||||||
|
|
||||||
|
Label.mixins(['text', 'line:border_', 'fill:background_']);
|
||||||
|
|
||||||
|
Label.define({
|
||||||
|
x: [p.Number],
|
||||||
|
x_units: [p.SpatialUnits, 'data'],
|
||||||
|
y: [p.Number],
|
||||||
|
y_units: [p.SpatialUnits, 'data'],
|
||||||
|
text: [p.String],
|
||||||
|
angle: [p.Angle, 0],
|
||||||
|
angle_units: [p.AngleUnits, 'rad'],
|
||||||
|
x_offset: [p.Number, 0],
|
||||||
|
y_offset: [p.Number, 0],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default'],
|
||||||
|
render_mode: [p.RenderMode, 'canvas']
|
||||||
|
});
|
||||||
|
|
||||||
|
Label.override({
|
||||||
|
background_fill_color: null,
|
||||||
|
border_line_color: null
|
||||||
|
});
|
||||||
|
|
||||||
|
return Label;
|
||||||
|
|
||||||
|
})(TextAnnotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Label,
|
||||||
|
View: LabelView
|
||||||
|
};
|
|
@ -0,0 +1,246 @@
|
||||||
|
var $, ColumnDataSource, LabelSet, LabelSetView, TextAnnotation, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
TextAnnotation = require("./text_annotation");
|
||||||
|
|
||||||
|
ColumnDataSource = require("../sources/column_data_source");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
LabelSetView = (function(superClass) {
|
||||||
|
extend(LabelSetView, superClass);
|
||||||
|
|
||||||
|
function LabelSetView() {
|
||||||
|
return LabelSetView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelSetView.prototype.initialize = function(options) {
|
||||||
|
var i, j, ref, results;
|
||||||
|
LabelSetView.__super__.initialize.call(this, options);
|
||||||
|
this.xmapper = this.plot_view.frame.get('x_mappers')[this.model.x_range_name];
|
||||||
|
this.ymapper = this.plot_view.frame.get('y_mappers')[this.model.y_range_name];
|
||||||
|
this.set_data();
|
||||||
|
if (this.model.render_mode === 'css') {
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = this._text.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
this.title_div = $("<div>").addClass('bk-annotation-child').hide();
|
||||||
|
results.push(this.title_div.appendTo(this.$el));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype.bind_bokeh_events = function() {
|
||||||
|
if (this.model.render_mode === 'css') {
|
||||||
|
this.listenTo(this.model, 'change', function() {
|
||||||
|
this.set_data();
|
||||||
|
return this.render();
|
||||||
|
});
|
||||||
|
return this.listenTo(this.model.source, 'change', function() {
|
||||||
|
this.set_data();
|
||||||
|
return this.render();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.listenTo(this.model, 'change', function() {
|
||||||
|
this.set_data();
|
||||||
|
return this.plot_view.request_render();
|
||||||
|
});
|
||||||
|
return this.listenTo(this.model.source, 'change', function() {
|
||||||
|
this.set_data();
|
||||||
|
return this.plot_view.request_render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype.set_data = function() {
|
||||||
|
LabelSetView.__super__.set_data.call(this, this.model.source);
|
||||||
|
return this.set_visuals(this.model.source);
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype._map_data = function() {
|
||||||
|
var sx, sy, vx, vy;
|
||||||
|
if (this.model.x_units === "data") {
|
||||||
|
vx = this.xmapper.v_map_to_target(this._x);
|
||||||
|
} else {
|
||||||
|
vx = this._x.slice(0);
|
||||||
|
}
|
||||||
|
sx = this.canvas.v_vx_to_sx(vx);
|
||||||
|
if (this.model.y_units === "data") {
|
||||||
|
vy = this.ymapper.v_map_to_target(this._y);
|
||||||
|
} else {
|
||||||
|
vy = this._y.slice(0);
|
||||||
|
}
|
||||||
|
sy = this.canvas.v_vy_to_sy(vy);
|
||||||
|
return [sx, sy];
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype.render = function() {
|
||||||
|
var ctx, i, j, k, ref, ref1, ref2, results, results1, sx, sy;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ref = this._map_data(), sx = ref[0], sy = ref[1];
|
||||||
|
if (this.model.render_mode === 'canvas') {
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref1 = this._text.length; 0 <= ref1 ? j < ref1 : j > ref1; i = 0 <= ref1 ? ++j : --j) {
|
||||||
|
results.push(this._v_canvas_text(ctx, i, this._text[i], sx[i] + this._x_offset[i], sy[i] - this._y_offset[i], this._angle[i]));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} else {
|
||||||
|
results1 = [];
|
||||||
|
for (i = k = 0, ref2 = this._text.length; 0 <= ref2 ? k < ref2 : k > ref2; i = 0 <= ref2 ? ++k : --k) {
|
||||||
|
results1.push(this._v_css_text(ctx, i, this._text[i], sx[i] + this._x_offset[i], sy[i] - this._y_offset[i], this._angle[i]));
|
||||||
|
}
|
||||||
|
return results1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype._get_size = function() {
|
||||||
|
var ctx, height, side, width;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
side = this.model.panel.side;
|
||||||
|
if (side === "above" || side === "below") {
|
||||||
|
height = ctx.measureText(this._text[0]).ascent;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
if (side === 'left' || side === 'right') {
|
||||||
|
width = ctx.measureText(this._text[0]).width;
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype._v_canvas_text = function(ctx, i, text, sx, sy, angle) {
|
||||||
|
var bbox_dims;
|
||||||
|
this.visuals.text.set_vectorize(ctx, i);
|
||||||
|
bbox_dims = this._calculate_bounding_box_dimensions(ctx, text);
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.translate(sx, sy);
|
||||||
|
ctx.rotate(angle);
|
||||||
|
ctx.rect(bbox_dims[0], bbox_dims[1], bbox_dims[2], bbox_dims[3]);
|
||||||
|
if (this.visuals.background_fill.doit) {
|
||||||
|
this.visuals.background_fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
this.visuals.border_line.set_vectorize(ctx, i);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
if (this.visuals.text.doit) {
|
||||||
|
this.visuals.text.set_vectorize(ctx, i);
|
||||||
|
ctx.fillText(text, 0, 0);
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
LabelSetView.prototype._v_css_text = function(ctx, i, text, sx, sy, angle) {
|
||||||
|
var bbox_dims, div_style, ld, line_dash;
|
||||||
|
this.visuals.text.set_vectorize(ctx, i);
|
||||||
|
bbox_dims = this._calculate_bounding_box_dimensions(ctx, text);
|
||||||
|
ld = this.visuals.border_line.line_dash.value();
|
||||||
|
if (_.isArray(ld)) {
|
||||||
|
if (ld.length < 2) {
|
||||||
|
line_dash = "solid";
|
||||||
|
} else {
|
||||||
|
line_dash = "dashed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.isString(ld)) {
|
||||||
|
line_dash = ld;
|
||||||
|
}
|
||||||
|
this.visuals.border_line.set_vectorize(ctx, i);
|
||||||
|
this.visuals.background_fill.set_vectorize(ctx, i);
|
||||||
|
div_style = {
|
||||||
|
'position': 'absolute',
|
||||||
|
'left': (sx + bbox_dims[0]) + "px",
|
||||||
|
'top': (sy + bbox_dims[1]) + "px",
|
||||||
|
'color': "" + (this.visuals.text.text_color.value()),
|
||||||
|
'opacity': "" + (this.visuals.text.text_alpha.value()),
|
||||||
|
'font': "" + (this.visuals.text.font_value()),
|
||||||
|
'line-height': "normal"
|
||||||
|
};
|
||||||
|
if (angle) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'transform': "rotate(" + angle + "rad)"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.visuals.background_fill.doit) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'background-color': "" + (this.visuals.background_fill.color_value())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'border-style': "" + line_dash,
|
||||||
|
'border-width': "" + (this.visuals.border_line.line_width.value()),
|
||||||
|
'border-color': "" + (this.visuals.border_line.color_value())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.$el.children().eq(i).html(text).css(div_style).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
return LabelSetView;
|
||||||
|
|
||||||
|
})(TextAnnotation.View);
|
||||||
|
|
||||||
|
LabelSet = (function(superClass) {
|
||||||
|
extend(LabelSet, superClass);
|
||||||
|
|
||||||
|
function LabelSet() {
|
||||||
|
return LabelSet.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelSet.prototype.default_view = LabelSetView;
|
||||||
|
|
||||||
|
LabelSet.prototype.type = 'Label';
|
||||||
|
|
||||||
|
LabelSet.mixins(['text', 'line:border_', 'fill:background_']);
|
||||||
|
|
||||||
|
LabelSet.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
LabelSet.define({
|
||||||
|
x_units: [p.SpatialUnits, 'data'],
|
||||||
|
y_units: [p.SpatialUnits, 'data'],
|
||||||
|
text: [
|
||||||
|
p.StringSpec, {
|
||||||
|
field: "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
angle: [p.AngleSpec, 0],
|
||||||
|
x_offset: [
|
||||||
|
p.NumberSpec, {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
y_offset: [
|
||||||
|
p.NumberSpec, {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
source: [
|
||||||
|
p.Instance, function() {
|
||||||
|
return new ColumnDataSource.Model();
|
||||||
|
}
|
||||||
|
],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default'],
|
||||||
|
render_mode: [p.RenderMode, 'canvas']
|
||||||
|
});
|
||||||
|
|
||||||
|
LabelSet.override({
|
||||||
|
background_fill_color: null,
|
||||||
|
border_line_color: null
|
||||||
|
});
|
||||||
|
|
||||||
|
return LabelSet;
|
||||||
|
|
||||||
|
})(TextAnnotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: LabelSet,
|
||||||
|
View: LabelSetView
|
||||||
|
};
|
|
@ -0,0 +1,241 @@
|
||||||
|
var Annotation, Legend, LegendView, _, get_text_height, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
get_text_height = require("../../core/util/text").get_text_height;
|
||||||
|
|
||||||
|
LegendView = (function(superClass) {
|
||||||
|
extend(LegendView, superClass);
|
||||||
|
|
||||||
|
function LegendView() {
|
||||||
|
return LegendView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LegendView.prototype.initialize = function(options) {
|
||||||
|
return LegendView.__super__.initialize.call(this, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
LegendView.prototype.compute_legend_bbox = function() {
|
||||||
|
var ctx, glyph_height, glyph_width, glyphs, h_range, i, label_height, label_standoff, label_width, legend_height, legend_margin, legend_name, legend_names, legend_padding, legend_spacing, legend_width, len, location, max_label_width, name, ref, v_range, width, x, y;
|
||||||
|
legend_names = (function() {
|
||||||
|
var i, len, ref, ref1, results;
|
||||||
|
ref = this.mget("legends");
|
||||||
|
results = [];
|
||||||
|
for (i = 0, len = ref.length; i < len; i++) {
|
||||||
|
ref1 = ref[i], legend_name = ref1[0], glyphs = ref1[1];
|
||||||
|
results.push(legend_name);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
glyph_height = this.mget('glyph_height');
|
||||||
|
glyph_width = this.mget('glyph_width');
|
||||||
|
label_height = this.mget('label_height');
|
||||||
|
label_width = this.mget('label_width');
|
||||||
|
this.max_label_height = _.max([get_text_height(this.visuals.label_text.font_value()).height, label_height, glyph_height]);
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
this.visuals.label_text.set_value(ctx);
|
||||||
|
this.text_widths = {};
|
||||||
|
for (i = 0, len = legend_names.length; i < len; i++) {
|
||||||
|
name = legend_names[i];
|
||||||
|
this.text_widths[name] = _.max([ctx.measureText(name).width, label_width]);
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
max_label_width = _.max(_.values(this.text_widths));
|
||||||
|
legend_margin = this.mget('legend_margin');
|
||||||
|
legend_padding = this.mget('legend_padding');
|
||||||
|
legend_spacing = this.mget('legend_spacing');
|
||||||
|
label_standoff = this.mget('label_standoff');
|
||||||
|
if (this.mget("orientation") === "vertical") {
|
||||||
|
legend_height = legend_names.length * this.max_label_height + (legend_names.length - 1) * legend_spacing + 2 * legend_padding;
|
||||||
|
legend_width = max_label_width + glyph_width + label_standoff + 2 * legend_padding;
|
||||||
|
} else {
|
||||||
|
legend_width = 2 * legend_padding + (legend_names.length - 1) * legend_spacing;
|
||||||
|
ref = this.text_widths;
|
||||||
|
for (name in ref) {
|
||||||
|
width = ref[name];
|
||||||
|
legend_width += _.max([width, label_width]) + glyph_width + label_standoff;
|
||||||
|
}
|
||||||
|
legend_height = this.max_label_height + 2 * legend_padding;
|
||||||
|
}
|
||||||
|
location = this.mget('location');
|
||||||
|
h_range = this.plot_view.frame.get('h_range');
|
||||||
|
v_range = this.plot_view.frame.get('v_range');
|
||||||
|
if (_.isString(location)) {
|
||||||
|
switch (location) {
|
||||||
|
case 'top_left':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'top_center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'top_right':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = v_range.get('end') - legend_margin;
|
||||||
|
break;
|
||||||
|
case 'right_center':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
break;
|
||||||
|
case 'bottom_right':
|
||||||
|
x = h_range.get('end') - legend_margin - legend_width;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'bottom_center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'bottom_left':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = v_range.get('start') + legend_margin + legend_height;
|
||||||
|
break;
|
||||||
|
case 'left_center':
|
||||||
|
x = h_range.get('start') + legend_margin;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
x = (h_range.get('end') + h_range.get('start')) / 2 - legend_width / 2;
|
||||||
|
y = (v_range.get('end') + v_range.get('start')) / 2 + legend_height / 2;
|
||||||
|
}
|
||||||
|
} else if (_.isArray(location) && location.length === 2) {
|
||||||
|
x = location[0], y = location[1];
|
||||||
|
}
|
||||||
|
x = this.plot_view.canvas.vx_to_sx(x);
|
||||||
|
y = this.plot_view.canvas.vy_to_sy(y);
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: legend_width,
|
||||||
|
height: legend_height
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
LegendView.prototype.render = function() {
|
||||||
|
var N, bbox, ctx, glyph_height, glyph_width, glyphs, i, idx, j, label_standoff, legend_name, legend_spacing, len, len1, orientation, panel_offset, ref, ref1, renderer, view, x1, x2, xoffset, y1, y2, yoffset;
|
||||||
|
if (this.model.legends.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bbox = this.compute_legend_bbox();
|
||||||
|
glyph_height = this.mget('glyph_height');
|
||||||
|
glyph_width = this.mget('glyph_width');
|
||||||
|
orientation = this.mget('orientation');
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
if (this.model.panel != null) {
|
||||||
|
panel_offset = this._get_panel_offset();
|
||||||
|
ctx.translate(panel_offset.x, panel_offset.y);
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(bbox.x, bbox.y, bbox.width, bbox.height);
|
||||||
|
this.visuals.background_fill.set_value(ctx);
|
||||||
|
ctx.fill();
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
this.visuals.border_line.set_value(ctx);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
N = this.mget("legends").length;
|
||||||
|
legend_spacing = this.mget('legend_spacing');
|
||||||
|
label_standoff = this.mget('label_standoff');
|
||||||
|
xoffset = yoffset = this.mget('legend_padding');
|
||||||
|
ref = this.mget("legends");
|
||||||
|
for (idx = i = 0, len = ref.length; i < len; idx = ++i) {
|
||||||
|
ref1 = ref[idx], legend_name = ref1[0], glyphs = ref1[1];
|
||||||
|
x1 = bbox.x + xoffset;
|
||||||
|
y1 = bbox.y + yoffset;
|
||||||
|
x2 = x1 + glyph_width;
|
||||||
|
y2 = y1 + glyph_height;
|
||||||
|
if (orientation === "vertical") {
|
||||||
|
yoffset += this.max_label_height + legend_spacing;
|
||||||
|
} else {
|
||||||
|
xoffset += this.text_widths[legend_name] + glyph_width + label_standoff + legend_spacing;
|
||||||
|
}
|
||||||
|
this.visuals.label_text.set_value(ctx);
|
||||||
|
ctx.fillText(legend_name, x2 + label_standoff, y1 + this.max_label_height / 2.0);
|
||||||
|
for (j = 0, len1 = glyphs.length; j < len1; j++) {
|
||||||
|
renderer = glyphs[j];
|
||||||
|
view = this.plot_view.renderer_views[renderer.id];
|
||||||
|
view.draw_legend(ctx, x1, x2, y1, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
LegendView.prototype._get_size = function() {
|
||||||
|
var bbox, side;
|
||||||
|
bbox = this.compute_legend_bbox();
|
||||||
|
side = this.model.panel.side;
|
||||||
|
if (side === 'above' || side === 'below') {
|
||||||
|
return bbox.height;
|
||||||
|
}
|
||||||
|
if (side === 'left' || side === 'right') {
|
||||||
|
return bbox.width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LegendView.prototype._get_panel_offset = function() {
|
||||||
|
var x, y;
|
||||||
|
x = this.model.panel._left._value;
|
||||||
|
y = this.model.panel._top._value;
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: -y
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return LegendView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
Legend = (function(superClass) {
|
||||||
|
extend(Legend, superClass);
|
||||||
|
|
||||||
|
function Legend() {
|
||||||
|
return Legend.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Legend.prototype.default_view = LegendView;
|
||||||
|
|
||||||
|
Legend.prototype.type = 'Legend';
|
||||||
|
|
||||||
|
Legend.mixins(['text:label_', 'line:border_', 'fill:background_']);
|
||||||
|
|
||||||
|
Legend.define({
|
||||||
|
legends: [p.Array, []],
|
||||||
|
orientation: [p.Orientation, 'vertical'],
|
||||||
|
location: [p.Any, 'top_right'],
|
||||||
|
label_standoff: [p.Number, 5],
|
||||||
|
glyph_height: [p.Number, 20],
|
||||||
|
glyph_width: [p.Number, 20],
|
||||||
|
label_height: [p.Number, 20],
|
||||||
|
label_width: [p.Number, 20],
|
||||||
|
legend_margin: [p.Number, 10],
|
||||||
|
legend_padding: [p.Number, 10],
|
||||||
|
legend_spacing: [p.Number, 3]
|
||||||
|
});
|
||||||
|
|
||||||
|
Legend.override({
|
||||||
|
border_line_color: "#e5e5e5",
|
||||||
|
border_line_alpha: 0.5,
|
||||||
|
border_line_width: 1,
|
||||||
|
background_fill_color: "#ffffff",
|
||||||
|
background_fill_alpha: 0.95,
|
||||||
|
label_text_font_size: "10pt",
|
||||||
|
label_text_baseline: "middle"
|
||||||
|
});
|
||||||
|
|
||||||
|
return Legend;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Legend,
|
||||||
|
View: LegendView
|
||||||
|
};
|
|
@ -0,0 +1,114 @@
|
||||||
|
var Annotation, PolyAnnotation, PolyAnnotationView, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
PolyAnnotationView = (function(superClass) {
|
||||||
|
extend(PolyAnnotationView, superClass);
|
||||||
|
|
||||||
|
function PolyAnnotationView() {
|
||||||
|
return PolyAnnotationView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyAnnotationView.prototype.bind_bokeh_events = function() {
|
||||||
|
this.listenTo(this.model, 'change', this.plot_view.request_render);
|
||||||
|
return this.listenTo(this.model, 'data_update', this.plot_view.request_render);
|
||||||
|
};
|
||||||
|
|
||||||
|
PolyAnnotationView.prototype.render = function(ctx) {
|
||||||
|
var canvas, i, j, ref, sx, sy, vx, vy, xs, ys;
|
||||||
|
xs = this.mget('xs');
|
||||||
|
ys = this.mget('ys');
|
||||||
|
if (xs.length !== ys.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (xs.length < 3 || ys.length < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
canvas = this.plot_view.canvas;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
for (i = j = 0, ref = xs.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
if (this.mget('xs_units') === 'screen') {
|
||||||
|
vx = xs[i];
|
||||||
|
}
|
||||||
|
if (this.mget('ys_units') === 'screen') {
|
||||||
|
vy = ys[i];
|
||||||
|
}
|
||||||
|
sx = canvas.vx_to_sx(vx);
|
||||||
|
sy = canvas.vy_to_sy(vy);
|
||||||
|
if (i === 0) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(sx, sy);
|
||||||
|
} else {
|
||||||
|
ctx.lineTo(sx, sy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_value(ctx);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_value(ctx);
|
||||||
|
return ctx.fill();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return PolyAnnotationView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
PolyAnnotation = (function(superClass) {
|
||||||
|
extend(PolyAnnotation, superClass);
|
||||||
|
|
||||||
|
function PolyAnnotation() {
|
||||||
|
return PolyAnnotation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyAnnotation.prototype.default_view = PolyAnnotationView;
|
||||||
|
|
||||||
|
PolyAnnotation.prototype.type = "PolyAnnotation";
|
||||||
|
|
||||||
|
PolyAnnotation.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
PolyAnnotation.define({
|
||||||
|
xs: [p.Array, []],
|
||||||
|
xs_units: [p.SpatialUnits, 'data'],
|
||||||
|
ys: [p.Array, []],
|
||||||
|
ys_units: [p.SpatialUnits, 'data'],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default']
|
||||||
|
});
|
||||||
|
|
||||||
|
PolyAnnotation.override({
|
||||||
|
fill_color: "#fff9ba",
|
||||||
|
fill_alpha: 0.4,
|
||||||
|
line_color: "#cccccc",
|
||||||
|
line_alpha: 0.3
|
||||||
|
});
|
||||||
|
|
||||||
|
PolyAnnotation.prototype.update = function(arg) {
|
||||||
|
var xs, ys;
|
||||||
|
xs = arg.xs, ys = arg.ys;
|
||||||
|
this.set({
|
||||||
|
xs: xs,
|
||||||
|
ys: ys
|
||||||
|
}, {
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
|
return this.trigger('data_update');
|
||||||
|
};
|
||||||
|
|
||||||
|
return PolyAnnotation;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: PolyAnnotation,
|
||||||
|
View: PolyAnnotationView
|
||||||
|
};
|
|
@ -0,0 +1,148 @@
|
||||||
|
var Annotation, Span, SpanView, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
SpanView = (function(superClass) {
|
||||||
|
extend(SpanView, superClass);
|
||||||
|
|
||||||
|
function SpanView() {
|
||||||
|
return SpanView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpanView.prototype.initialize = function(options) {
|
||||||
|
SpanView.__super__.initialize.call(this, options);
|
||||||
|
this.$el.appendTo(this.plot_view.$el.find('div.bk-canvas-overlays'));
|
||||||
|
this.$el.css({
|
||||||
|
position: 'absolute'
|
||||||
|
});
|
||||||
|
return this.$el.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
SpanView.prototype.bind_bokeh_events = function() {
|
||||||
|
if (this.mget('for_hover')) {
|
||||||
|
return this.listenTo(this.model, 'change:computed_location', this._draw_span);
|
||||||
|
} else {
|
||||||
|
if (this.mget('render_mode') === 'canvas') {
|
||||||
|
return this.listenTo(this.model, 'change:location', this.plot_view.request_render);
|
||||||
|
} else {
|
||||||
|
return this.listenTo(this.model, 'change:location', this._draw_span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpanView.prototype.render = function() {
|
||||||
|
return this._draw_span();
|
||||||
|
};
|
||||||
|
|
||||||
|
SpanView.prototype._draw_span = function() {
|
||||||
|
var canvas, ctx, frame, height, loc, sleft, stop, width, xmapper, ymapper;
|
||||||
|
if (this.mget('for_hover')) {
|
||||||
|
loc = this.mget('computed_location');
|
||||||
|
} else {
|
||||||
|
loc = this.mget('location');
|
||||||
|
}
|
||||||
|
if (loc == null) {
|
||||||
|
this.$el.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame = this.plot_model.get('frame');
|
||||||
|
canvas = this.plot_model.get('canvas');
|
||||||
|
xmapper = this.plot_view.frame.get('x_mappers')[this.mget("x_range_name")];
|
||||||
|
ymapper = this.plot_view.frame.get('y_mappers')[this.mget("y_range_name")];
|
||||||
|
if (this.mget('dimension') === 'width') {
|
||||||
|
stop = canvas.vy_to_sy(this._calc_dim(loc, ymapper));
|
||||||
|
sleft = canvas.vx_to_sx(frame.get('left'));
|
||||||
|
width = frame.get('width');
|
||||||
|
height = this.model.properties.line_width.value();
|
||||||
|
} else {
|
||||||
|
stop = canvas.vy_to_sy(frame.get('top'));
|
||||||
|
sleft = canvas.vx_to_sx(this._calc_dim(loc, xmapper));
|
||||||
|
width = this.model.properties.line_width.value();
|
||||||
|
height = frame.get('height');
|
||||||
|
}
|
||||||
|
if (this.mget("render_mode") === "css") {
|
||||||
|
this.$el.css({
|
||||||
|
'top': stop,
|
||||||
|
'left': sleft,
|
||||||
|
'width': width + "px",
|
||||||
|
'height': height + "px",
|
||||||
|
'z-index': 1000,
|
||||||
|
'background-color': this.model.properties.line_color.value(),
|
||||||
|
'opacity': this.model.properties.line_alpha.value()
|
||||||
|
});
|
||||||
|
return this.$el.show();
|
||||||
|
} else if (this.mget("render_mode") === "canvas") {
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
this.visuals.line.set_value(ctx);
|
||||||
|
ctx.moveTo(sleft, stop);
|
||||||
|
if (this.mget('dimension') === "width") {
|
||||||
|
ctx.lineTo(sleft + width, stop);
|
||||||
|
} else {
|
||||||
|
ctx.lineTo(sleft, stop + height);
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
return ctx.restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpanView.prototype._calc_dim = function(location, mapper) {
|
||||||
|
var vdim;
|
||||||
|
if (this.mget('location_units') === 'data') {
|
||||||
|
vdim = mapper.map_to_target(location);
|
||||||
|
} else {
|
||||||
|
vdim = location;
|
||||||
|
}
|
||||||
|
return vdim;
|
||||||
|
};
|
||||||
|
|
||||||
|
return SpanView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
Span = (function(superClass) {
|
||||||
|
extend(Span, superClass);
|
||||||
|
|
||||||
|
function Span() {
|
||||||
|
return Span.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Span.prototype.default_view = SpanView;
|
||||||
|
|
||||||
|
Span.prototype.type = 'Span';
|
||||||
|
|
||||||
|
Span.mixins(['line']);
|
||||||
|
|
||||||
|
Span.define({
|
||||||
|
render_mode: [p.RenderMode, 'canvas'],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default'],
|
||||||
|
location: [p.Number, null],
|
||||||
|
location_units: [p.SpatialUnits, 'data'],
|
||||||
|
dimension: [p.Dimension, 'width']
|
||||||
|
});
|
||||||
|
|
||||||
|
Span.override({
|
||||||
|
line_color: 'black'
|
||||||
|
});
|
||||||
|
|
||||||
|
Span.internal({
|
||||||
|
for_hover: [p.Boolean, false],
|
||||||
|
computed_location: [p.Number, null]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Span;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Span,
|
||||||
|
View: SpanView
|
||||||
|
};
|
|
@ -0,0 +1,186 @@
|
||||||
|
var Annotation, TextAnnotation, TextAnnotationView, _, get_text_height, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
get_text_height = require("../../core/util/text").get_text_height;
|
||||||
|
|
||||||
|
TextAnnotationView = (function(superClass) {
|
||||||
|
extend(TextAnnotationView, superClass);
|
||||||
|
|
||||||
|
function TextAnnotationView() {
|
||||||
|
return TextAnnotationView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAnnotationView.prototype.initialize = function(options) {
|
||||||
|
TextAnnotationView.__super__.initialize.call(this, options);
|
||||||
|
this.canvas = this.plot_model.get('canvas');
|
||||||
|
this.frame = this.plot_model.get('frame');
|
||||||
|
if (this.mget('render_mode') === 'css') {
|
||||||
|
this.$el.addClass('bk-annotation');
|
||||||
|
return this.$el.appendTo(this.plot_view.$el.find('div.bk-canvas-overlays'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype.bind_bokeh_events = function() {
|
||||||
|
if (this.mget('render_mode') === 'css') {
|
||||||
|
return this.listenTo(this.model, 'change', this.render);
|
||||||
|
} else {
|
||||||
|
return this.listenTo(this.model, 'change', this.plot_view.request_render);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype._calculate_text_dimensions = function(ctx, text) {
|
||||||
|
var height, width;
|
||||||
|
width = ctx.measureText(text).width;
|
||||||
|
height = get_text_height(this.visuals.text.font_value()).height;
|
||||||
|
return [width, height];
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype._calculate_bounding_box_dimensions = function(ctx, text) {
|
||||||
|
var height, ref, width, x_offset, y_offset;
|
||||||
|
ref = this._calculate_text_dimensions(ctx, text), width = ref[0], height = ref[1];
|
||||||
|
switch (ctx.textAlign) {
|
||||||
|
case 'left':
|
||||||
|
x_offset = 0;
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
x_offset = -width / 2;
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
x_offset = -width;
|
||||||
|
}
|
||||||
|
switch (ctx.textBaseline) {
|
||||||
|
case 'top':
|
||||||
|
y_offset = 0.0;
|
||||||
|
break;
|
||||||
|
case 'middle':
|
||||||
|
y_offset = -0.5 * height;
|
||||||
|
break;
|
||||||
|
case 'bottom':
|
||||||
|
y_offset = -1.0 * height;
|
||||||
|
break;
|
||||||
|
case 'alphabetic':
|
||||||
|
y_offset = -0.8 * height;
|
||||||
|
break;
|
||||||
|
case 'hanging':
|
||||||
|
y_offset = -0.17 * height;
|
||||||
|
break;
|
||||||
|
case 'ideographic':
|
||||||
|
y_offset = -0.83 * height;
|
||||||
|
}
|
||||||
|
return [x_offset, y_offset, width, height];
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype._get_size = function() {
|
||||||
|
var ctx;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
return ctx.measureText(this.mget('text')).ascent;
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype.render = function() {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype._canvas_text = function(ctx, text, sx, sy, angle) {
|
||||||
|
var bbox_dims;
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
bbox_dims = this._calculate_bounding_box_dimensions(ctx, text);
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.translate(sx, sy);
|
||||||
|
if (angle) {
|
||||||
|
ctx.rotate(angle);
|
||||||
|
}
|
||||||
|
ctx.rect(bbox_dims[0], bbox_dims[1], bbox_dims[2], bbox_dims[3]);
|
||||||
|
if (this.visuals.background_fill.doit) {
|
||||||
|
this.visuals.background_fill.set_value(ctx);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
this.visuals.border_line.set_value(ctx);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
if (this.visuals.text.doit) {
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
ctx.fillText(text, 0, 0);
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAnnotationView.prototype._css_text = function(ctx, text, sx, sy, angle) {
|
||||||
|
var bbox_dims, div_style, ld, line_dash;
|
||||||
|
this.$el.hide();
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
bbox_dims = this._calculate_bounding_box_dimensions(ctx, text);
|
||||||
|
ld = this.visuals.border_line.line_dash.value();
|
||||||
|
if (_.isArray(ld)) {
|
||||||
|
if (ld.length < 2) {
|
||||||
|
line_dash = "solid";
|
||||||
|
} else {
|
||||||
|
line_dash = "dashed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.isString(ld)) {
|
||||||
|
line_dash = ld;
|
||||||
|
}
|
||||||
|
this.visuals.border_line.set_value(ctx);
|
||||||
|
this.visuals.background_fill.set_value(ctx);
|
||||||
|
div_style = {
|
||||||
|
'position': 'absolute',
|
||||||
|
'left': (sx + bbox_dims[0]) + "px",
|
||||||
|
'top': (sy + bbox_dims[1]) + "px",
|
||||||
|
'color': "" + (this.visuals.text.text_color.value()),
|
||||||
|
'opacity': "" + (this.visuals.text.text_alpha.value()),
|
||||||
|
'font': "" + (this.visuals.text.font_value()),
|
||||||
|
'line-height': "normal"
|
||||||
|
};
|
||||||
|
if (angle) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'transform': "rotate(" + angle + "rad)"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.visuals.background_fill.doit) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'background-color': "" + (this.visuals.background_fill.color_value())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.visuals.border_line.doit) {
|
||||||
|
_.extend(div_style, {
|
||||||
|
'border-style': "" + line_dash,
|
||||||
|
'border-width': "" + (this.visuals.border_line.line_width.value()),
|
||||||
|
'border-color': "" + (this.visuals.border_line.color_value())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.$el.html(text).css(div_style).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
return TextAnnotationView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
TextAnnotation = (function(superClass) {
|
||||||
|
extend(TextAnnotation, superClass);
|
||||||
|
|
||||||
|
function TextAnnotation() {
|
||||||
|
return TextAnnotation.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAnnotation.prototype.type = 'TextAnnotation';
|
||||||
|
|
||||||
|
TextAnnotation.prototype.default_view = TextAnnotationView;
|
||||||
|
|
||||||
|
return TextAnnotation;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: TextAnnotation,
|
||||||
|
View: TextAnnotationView
|
||||||
|
};
|
|
@ -0,0 +1,146 @@
|
||||||
|
var TextAnnotation, Title, TitleView, Visuals, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
TextAnnotation = require("./text_annotation");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Visuals = require("../renderers/renderer").Visuals;
|
||||||
|
|
||||||
|
TitleView = (function(superClass) {
|
||||||
|
extend(TitleView, superClass);
|
||||||
|
|
||||||
|
function TitleView() {
|
||||||
|
return TitleView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleView.prototype.initialize = function(options) {
|
||||||
|
var ctx;
|
||||||
|
TitleView.__super__.initialize.call(this, options);
|
||||||
|
this.visuals.text = new Visuals.text({
|
||||||
|
obj: this.model,
|
||||||
|
prefix: ""
|
||||||
|
});
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
this.model.panel.apply_label_text_heuristics(ctx, 'justified');
|
||||||
|
this.model.text_baseline = ctx.textBaseline;
|
||||||
|
this.model.text_align = this.model.align;
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
TitleView.prototype._get_computed_location = function() {
|
||||||
|
var height, ref, sx, sy, vx, vy, width;
|
||||||
|
ref = this._calculate_text_dimensions(this.plot_view.canvas_view.ctx, this.text), width = ref[0], height = ref[1];
|
||||||
|
switch (this.model.panel.side) {
|
||||||
|
case 'left':
|
||||||
|
vx = 0;
|
||||||
|
vy = this._get_text_location(this.mget('align'), this.frame.get('v_range')) + this.mget('offset');
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
vx = this.canvas.get('right') - 1;
|
||||||
|
vy = this.canvas.get('height') - this._get_text_location(this.mget('align'), this.frame.get('v_range')) - this.mget('offset');
|
||||||
|
break;
|
||||||
|
case 'above':
|
||||||
|
vx = this._get_text_location(this.mget('align'), this.frame.get('h_range')) + this.mget('offset');
|
||||||
|
vy = this.canvas.get('top') - 10;
|
||||||
|
break;
|
||||||
|
case 'below':
|
||||||
|
vx = this._get_text_location(this.mget('align'), this.frame.get('h_range')) + this.mget('offset');
|
||||||
|
vy = 0;
|
||||||
|
}
|
||||||
|
sx = this.canvas.vx_to_sx(vx);
|
||||||
|
sy = this.canvas.vy_to_sy(vy);
|
||||||
|
return [sx, sy];
|
||||||
|
};
|
||||||
|
|
||||||
|
TitleView.prototype._get_text_location = function(alignment, range) {
|
||||||
|
var text_location;
|
||||||
|
switch (alignment) {
|
||||||
|
case 'left':
|
||||||
|
text_location = range.get('start');
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
text_location = (range.get('end') + range.get('start')) / 2;
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
text_location = range.get('end');
|
||||||
|
}
|
||||||
|
return text_location;
|
||||||
|
};
|
||||||
|
|
||||||
|
TitleView.prototype.render = function() {
|
||||||
|
var angle, ctx, ref, sx, sy;
|
||||||
|
angle = this.model.panel.get_label_angle_heuristic('parallel');
|
||||||
|
ref = this._get_computed_location(), sx = ref[0], sy = ref[1];
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
if (this.model.text === "" || this.model.text === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.model.render_mode === 'canvas') {
|
||||||
|
return this._canvas_text(ctx, this.model.text, sx, sy, angle);
|
||||||
|
} else {
|
||||||
|
return this._css_text(ctx, this.model.text, sx, sy, angle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TitleView.prototype._get_size = function() {
|
||||||
|
var ctx, text;
|
||||||
|
text = this.model.text;
|
||||||
|
if (text === "" || text === null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
this.visuals.text.set_value(ctx);
|
||||||
|
return ctx.measureText(text).ascent + 10;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TitleView;
|
||||||
|
|
||||||
|
})(TextAnnotation.View);
|
||||||
|
|
||||||
|
Title = (function(superClass) {
|
||||||
|
extend(Title, superClass);
|
||||||
|
|
||||||
|
function Title() {
|
||||||
|
return Title.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Title.prototype.default_view = TitleView;
|
||||||
|
|
||||||
|
Title.prototype.type = 'Title';
|
||||||
|
|
||||||
|
Title.mixins(['line:border_', 'fill:background_']);
|
||||||
|
|
||||||
|
Title.define({
|
||||||
|
text: [p.String],
|
||||||
|
text_font: [p.Font, 'helvetica'],
|
||||||
|
text_font_size: [p.FontSizeSpec, '10pt'],
|
||||||
|
text_font_style: [p.FontStyle, 'bold'],
|
||||||
|
text_color: [p.ColorSpec, '#444444'],
|
||||||
|
text_alpha: [p.NumberSpec, 1.0],
|
||||||
|
align: [p.TextAlign, 'left'],
|
||||||
|
offset: [p.Number, 0],
|
||||||
|
render_mode: [p.RenderMode, 'canvas']
|
||||||
|
});
|
||||||
|
|
||||||
|
Title.override({
|
||||||
|
background_fill_color: null,
|
||||||
|
border_line_color: null
|
||||||
|
});
|
||||||
|
|
||||||
|
Title.internal({
|
||||||
|
text_align: [p.TextAlign, 'left'],
|
||||||
|
text_baseline: [p.TextBaseline, 'bottom']
|
||||||
|
});
|
||||||
|
|
||||||
|
return Title;
|
||||||
|
|
||||||
|
})(TextAnnotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Title,
|
||||||
|
View: TitleView
|
||||||
|
};
|
|
@ -0,0 +1,168 @@
|
||||||
|
var $, Annotation, Tooltip, TooltipView, _, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
$ = require("jquery");
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Annotation = require("./annotation");
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
TooltipView = (function(superClass) {
|
||||||
|
extend(TooltipView, superClass);
|
||||||
|
|
||||||
|
function TooltipView() {
|
||||||
|
return TooltipView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
TooltipView.prototype.className = "bk-tooltip";
|
||||||
|
|
||||||
|
TooltipView.prototype.initialize = function(options) {
|
||||||
|
TooltipView.__super__.initialize.call(this, options);
|
||||||
|
this.$el.appendTo(this.plot_view.$el.find('div.bk-canvas-overlays'));
|
||||||
|
this.$el.css({
|
||||||
|
'z-index': 1010
|
||||||
|
});
|
||||||
|
return this.$el.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
TooltipView.prototype.bind_bokeh_events = function() {
|
||||||
|
return this.listenTo(this.model, 'change:data', this._draw_tips);
|
||||||
|
};
|
||||||
|
|
||||||
|
TooltipView.prototype.render = function() {
|
||||||
|
return this._draw_tips();
|
||||||
|
};
|
||||||
|
|
||||||
|
TooltipView.prototype._draw_tips = function() {
|
||||||
|
var arrow_size, attachment, bottom, content, data, height, i, left, len, side, sx, sy, tip, top, val, vx, vy, width;
|
||||||
|
data = this.model.data;
|
||||||
|
this.$el.empty();
|
||||||
|
this.$el.hide();
|
||||||
|
this.$el.toggleClass("bk-tooltip-custom", this.mget("custom"));
|
||||||
|
if (_.isEmpty(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = 0, len = data.length; i < len; i++) {
|
||||||
|
val = data[i];
|
||||||
|
vx = val[0], vy = val[1], content = val[2];
|
||||||
|
if (this.mget('inner_only') && !this.plot_view.frame.contains(vx, vy)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tip = $('<div />').appendTo(this.$el);
|
||||||
|
tip.append(content);
|
||||||
|
}
|
||||||
|
sx = this.plot_view.mget('canvas').vx_to_sx(vx);
|
||||||
|
sy = this.plot_view.mget('canvas').vy_to_sy(vy);
|
||||||
|
attachment = this.model.attachment;
|
||||||
|
switch (attachment) {
|
||||||
|
case "horizontal":
|
||||||
|
width = this.plot_view.frame.get('width');
|
||||||
|
left = this.plot_view.frame.get('left');
|
||||||
|
if (vx - left < width / 2) {
|
||||||
|
side = 'right';
|
||||||
|
} else {
|
||||||
|
side = 'left';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "vertical":
|
||||||
|
height = this.plot_view.frame.get('height');
|
||||||
|
bottom = this.plot_view.frame.get('bottom');
|
||||||
|
if (vy - bottom < height / 2) {
|
||||||
|
side = 'below';
|
||||||
|
} else {
|
||||||
|
side = 'above';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
side = attachment;
|
||||||
|
}
|
||||||
|
this.$el.removeClass('bk-right bk-left bk-above bk-below');
|
||||||
|
arrow_size = 10;
|
||||||
|
switch (side) {
|
||||||
|
case "right":
|
||||||
|
this.$el.addClass("bk-left");
|
||||||
|
left = sx + (this.$el.outerWidth() - this.$el.innerWidth()) + arrow_size;
|
||||||
|
top = sy - this.$el.outerHeight() / 2;
|
||||||
|
break;
|
||||||
|
case "left":
|
||||||
|
this.$el.addClass("bk-right");
|
||||||
|
left = sx - this.$el.outerWidth() - arrow_size;
|
||||||
|
top = sy - this.$el.outerHeight() / 2;
|
||||||
|
break;
|
||||||
|
case "above":
|
||||||
|
this.$el.addClass("bk-above");
|
||||||
|
top = sy + (this.$el.outerHeight() - this.$el.innerHeight()) + arrow_size;
|
||||||
|
left = Math.round(sx - this.$el.outerWidth() / 2);
|
||||||
|
break;
|
||||||
|
case "below":
|
||||||
|
this.$el.addClass("bk-below");
|
||||||
|
top = sy - this.$el.outerHeight() - arrow_size;
|
||||||
|
left = Math.round(sx - this.$el.outerWidth() / 2);
|
||||||
|
}
|
||||||
|
if (this.model.show_arrow) {
|
||||||
|
this.$el.addClass("bk-tooltip-arrow");
|
||||||
|
}
|
||||||
|
if (this.$el.children().length > 0) {
|
||||||
|
this.$el.css({
|
||||||
|
top: top,
|
||||||
|
left: left
|
||||||
|
});
|
||||||
|
return this.$el.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TooltipView;
|
||||||
|
|
||||||
|
})(Annotation.View);
|
||||||
|
|
||||||
|
Tooltip = (function(superClass) {
|
||||||
|
extend(Tooltip, superClass);
|
||||||
|
|
||||||
|
function Tooltip() {
|
||||||
|
return Tooltip.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip.prototype.default_view = TooltipView;
|
||||||
|
|
||||||
|
Tooltip.prototype.type = 'Tooltip';
|
||||||
|
|
||||||
|
Tooltip.define({
|
||||||
|
attachment: [p.String, 'horizontal'],
|
||||||
|
inner_only: [p.Bool, true],
|
||||||
|
show_arrow: [p.Bool, true]
|
||||||
|
});
|
||||||
|
|
||||||
|
Tooltip.override({
|
||||||
|
level: 'overlay'
|
||||||
|
});
|
||||||
|
|
||||||
|
Tooltip.internal({
|
||||||
|
data: [p.Any, []],
|
||||||
|
custom: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
Tooltip.prototype.clear = function() {
|
||||||
|
return this.data = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
Tooltip.prototype.add = function(vx, vy, content) {
|
||||||
|
var data;
|
||||||
|
data = this.data;
|
||||||
|
data.push([vx, vy, content]);
|
||||||
|
this.data = data;
|
||||||
|
return this.trigger('change:data');
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tooltip;
|
||||||
|
|
||||||
|
})(Annotation.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Tooltip,
|
||||||
|
View: TooltipView
|
||||||
|
};
|
|
@ -0,0 +1,467 @@
|
||||||
|
var Axis, AxisView, GE, GuideRenderer, Renderer, SidePanel, _, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
SidePanel = require("../../core/layout/side_panel");
|
||||||
|
|
||||||
|
GuideRenderer = require("../renderers/guide_renderer");
|
||||||
|
|
||||||
|
Renderer = require("../renderers/renderer");
|
||||||
|
|
||||||
|
GE = require("../../core/layout/solver").GE;
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
AxisView = (function(superClass) {
|
||||||
|
extend(AxisView, superClass);
|
||||||
|
|
||||||
|
function AxisView() {
|
||||||
|
return AxisView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisView.prototype.initialize = function(options) {
|
||||||
|
AxisView.__super__.initialize.call(this, options);
|
||||||
|
this._x_range_name = this.mget('x_range_name');
|
||||||
|
return this._y_range_name = this.mget('y_range_name');
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype.render = function() {
|
||||||
|
var ctx;
|
||||||
|
if (this.model.visible === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
ctx.save();
|
||||||
|
this._draw_rule(ctx);
|
||||||
|
this._draw_major_ticks(ctx);
|
||||||
|
this._draw_minor_ticks(ctx);
|
||||||
|
this._draw_major_labels(ctx);
|
||||||
|
this._draw_axis_label(ctx);
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype.bind_bokeh_events = function() {
|
||||||
|
return this.listenTo(this.model, 'change', this.plot_view.request_render);
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._get_size = function() {
|
||||||
|
return this._tick_extent() + this._tick_label_extent() + this._axis_label_extent();
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._draw_rule = function(ctx) {
|
||||||
|
var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, sx, sy, x, xoff, y, yoff;
|
||||||
|
if (!this.visuals.axis_line.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ref = coords = this.mget('rule_coords'), x = ref[0], y = ref[1];
|
||||||
|
ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1];
|
||||||
|
ref2 = this.mget('normals'), nx = ref2[0], ny = ref2[1];
|
||||||
|
ref3 = this.mget('offsets'), xoff = ref3[0], yoff = ref3[1];
|
||||||
|
this.visuals.axis_line.set_value(ctx);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(Math.round(sx[0] + nx * xoff), Math.round(sy[0] + ny * yoff));
|
||||||
|
for (i = k = 1, ref4 = sx.length; 1 <= ref4 ? k < ref4 : k > ref4; i = 1 <= ref4 ? ++k : --k) {
|
||||||
|
ctx.lineTo(Math.round(sx[i] + nx * xoff), Math.round(sy[i] + ny * yoff));
|
||||||
|
}
|
||||||
|
return ctx.stroke();
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._draw_major_ticks = function(ctx) {
|
||||||
|
var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, results, sx, sy, tin, tout, x, xoff, y, yoff;
|
||||||
|
if (!this.visuals.major_tick_line.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
coords = this.mget('tick_coords');
|
||||||
|
ref = coords.major, x = ref[0], y = ref[1];
|
||||||
|
ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1];
|
||||||
|
ref2 = this.mget('normals'), nx = ref2[0], ny = ref2[1];
|
||||||
|
ref3 = this.mget('offsets'), xoff = ref3[0], yoff = ref3[1];
|
||||||
|
tin = this.mget('major_tick_in');
|
||||||
|
tout = this.mget('major_tick_out');
|
||||||
|
this.visuals.major_tick_line.set_value(ctx);
|
||||||
|
results = [];
|
||||||
|
for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(Math.round(sx[i] + nx * tout + nx * xoff), Math.round(sy[i] + ny * tout + ny * yoff));
|
||||||
|
ctx.lineTo(Math.round(sx[i] - nx * tin + nx * xoff), Math.round(sy[i] - ny * tin + ny * yoff));
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._draw_minor_ticks = function(ctx) {
|
||||||
|
var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, results, sx, sy, tin, tout, x, xoff, y, yoff;
|
||||||
|
if (!this.visuals.minor_tick_line.doit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
coords = this.mget('tick_coords');
|
||||||
|
ref = coords.minor, x = ref[0], y = ref[1];
|
||||||
|
ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1];
|
||||||
|
ref2 = this.mget('normals'), nx = ref2[0], ny = ref2[1];
|
||||||
|
ref3 = this.mget('offsets'), xoff = ref3[0], yoff = ref3[1];
|
||||||
|
tin = this.mget('minor_tick_in');
|
||||||
|
tout = this.mget('minor_tick_out');
|
||||||
|
this.visuals.minor_tick_line.set_value(ctx);
|
||||||
|
results = [];
|
||||||
|
for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(Math.round(sx[i] + nx * tout + nx * xoff), Math.round(sy[i] + ny * tout + ny * yoff));
|
||||||
|
ctx.lineTo(Math.round(sx[i] - nx * tin + nx * xoff), Math.round(sy[i] - ny * tin + ny * yoff));
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._draw_major_labels = function(ctx) {
|
||||||
|
var angle, coords, dim, i, k, labels, nx, ny, orient, ref, ref1, ref2, ref3, ref4, results, side, standoff, sx, sy, x, xoff, y, yoff;
|
||||||
|
coords = this.mget('tick_coords');
|
||||||
|
ref = coords.major, x = ref[0], y = ref[1];
|
||||||
|
ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1];
|
||||||
|
ref2 = this.mget('normals'), nx = ref2[0], ny = ref2[1];
|
||||||
|
ref3 = this.mget('offsets'), xoff = ref3[0], yoff = ref3[1];
|
||||||
|
dim = this.mget('dimension');
|
||||||
|
side = this.mget('panel_side');
|
||||||
|
orient = this.mget('major_label_orientation');
|
||||||
|
if (_.isString(orient)) {
|
||||||
|
angle = this.model.panel.get_label_angle_heuristic(orient);
|
||||||
|
} else {
|
||||||
|
angle = -orient;
|
||||||
|
}
|
||||||
|
standoff = this._tick_extent() + this.mget('major_label_standoff');
|
||||||
|
labels = this.mget('formatter').doFormat(coords.major[dim]);
|
||||||
|
this.visuals.major_label_text.set_value(ctx);
|
||||||
|
this.model.panel.apply_label_text_heuristics(ctx, orient);
|
||||||
|
results = [];
|
||||||
|
for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) {
|
||||||
|
if (angle) {
|
||||||
|
ctx.translate(sx[i] + nx * standoff + nx * xoff, sy[i] + ny * standoff + ny * yoff);
|
||||||
|
ctx.rotate(angle);
|
||||||
|
ctx.fillText(labels[i], 0, 0);
|
||||||
|
ctx.rotate(-angle);
|
||||||
|
results.push(ctx.translate(-sx[i] - nx * standoff + nx * xoff, -sy[i] - ny * standoff + ny * yoff));
|
||||||
|
} else {
|
||||||
|
results.push(ctx.fillText(labels[i], Math.round(sx[i] + nx * standoff + nx * xoff), Math.round(sy[i] + ny * standoff + ny * yoff)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._draw_axis_label = function(ctx) {
|
||||||
|
var angle, label, nx, ny, orient, ref, ref1, ref2, ref3, side, standoff, sx, sy, x, xoff, y, yoff;
|
||||||
|
label = this.mget('axis_label');
|
||||||
|
if (label == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ref = this.mget('rule_coords'), x = ref[0], y = ref[1];
|
||||||
|
ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1];
|
||||||
|
ref2 = this.mget('normals'), nx = ref2[0], ny = ref2[1];
|
||||||
|
ref3 = this.mget('offsets'), xoff = ref3[0], yoff = ref3[1];
|
||||||
|
side = this.mget('panel_side');
|
||||||
|
orient = 'parallel';
|
||||||
|
angle = this.model.panel.get_label_angle_heuristic(orient);
|
||||||
|
standoff = this._tick_extent() + this._tick_label_extent() + this.mget('axis_label_standoff');
|
||||||
|
sx = (sx[0] + sx[sx.length - 1]) / 2;
|
||||||
|
sy = (sy[0] + sy[sy.length - 1]) / 2;
|
||||||
|
this.visuals.axis_label_text.set_value(ctx);
|
||||||
|
this.model.panel.apply_label_text_heuristics(ctx, orient);
|
||||||
|
x = sx + nx * standoff + nx * xoff;
|
||||||
|
y = sy + ny * standoff + ny * yoff;
|
||||||
|
if (isNaN(x) || isNaN(y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (angle) {
|
||||||
|
ctx.translate(x, y);
|
||||||
|
ctx.rotate(angle);
|
||||||
|
ctx.fillText(label, 0, 0);
|
||||||
|
ctx.rotate(-angle);
|
||||||
|
return ctx.translate(-x, -y);
|
||||||
|
} else {
|
||||||
|
return ctx.fillText(label, x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._tick_extent = function() {
|
||||||
|
return this.mget('major_tick_out');
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._tick_label_extent = function() {
|
||||||
|
var angle, c, coords, ctx, dim, extent, h, hfactor, hscale, i, k, labels, orient, ref, s, side, val, w, wfactor;
|
||||||
|
extent = 0;
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
dim = this.mget('dimension');
|
||||||
|
coords = this.mget('tick_coords').major;
|
||||||
|
side = this.mget('panel_side');
|
||||||
|
orient = this.mget('major_label_orientation');
|
||||||
|
labels = this.mget('formatter').doFormat(coords[dim]);
|
||||||
|
this.visuals.major_label_text.set_value(ctx);
|
||||||
|
if (_.isString(orient)) {
|
||||||
|
hscale = 1;
|
||||||
|
angle = this.model.panel.get_label_angle_heuristic(orient);
|
||||||
|
} else {
|
||||||
|
hscale = 2;
|
||||||
|
angle = -orient;
|
||||||
|
}
|
||||||
|
angle = Math.abs(angle);
|
||||||
|
c = Math.cos(angle);
|
||||||
|
s = Math.sin(angle);
|
||||||
|
if (side === "above" || side === "below") {
|
||||||
|
wfactor = s;
|
||||||
|
hfactor = c;
|
||||||
|
} else {
|
||||||
|
wfactor = c;
|
||||||
|
hfactor = s;
|
||||||
|
}
|
||||||
|
for (i = k = 0, ref = labels.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
|
||||||
|
if (labels[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
w = ctx.measureText(labels[i]).width * 1.1;
|
||||||
|
h = ctx.measureText(labels[i]).ascent * 0.9;
|
||||||
|
val = w * wfactor + (h / hscale) * hfactor;
|
||||||
|
if (val > extent) {
|
||||||
|
extent = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extent > 0) {
|
||||||
|
extent += this.mget('major_label_standoff');
|
||||||
|
}
|
||||||
|
return extent;
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisView.prototype._axis_label_extent = function() {
|
||||||
|
var angle, axis_label, c, ctx, extent, h, orient, s, side, w;
|
||||||
|
extent = 0;
|
||||||
|
side = this.mget('panel_side');
|
||||||
|
axis_label = this.mget('axis_label');
|
||||||
|
orient = 'parallel';
|
||||||
|
ctx = this.plot_view.canvas_view.ctx;
|
||||||
|
this.visuals.axis_label_text.set_value(ctx);
|
||||||
|
angle = Math.abs(this.model.panel.get_label_angle_heuristic(orient));
|
||||||
|
c = Math.cos(angle);
|
||||||
|
s = Math.sin(angle);
|
||||||
|
if (axis_label) {
|
||||||
|
extent += this.mget('axis_label_standoff');
|
||||||
|
this.visuals.axis_label_text.set_value(ctx);
|
||||||
|
w = ctx.measureText(axis_label).width * 1.1;
|
||||||
|
h = ctx.measureText(axis_label).ascent * 0.9;
|
||||||
|
if (side === "above" || side === "below") {
|
||||||
|
extent += w * s + h * c;
|
||||||
|
} else {
|
||||||
|
extent += w * c + h * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extent;
|
||||||
|
};
|
||||||
|
|
||||||
|
return AxisView;
|
||||||
|
|
||||||
|
})(Renderer.View);
|
||||||
|
|
||||||
|
Axis = (function(superClass) {
|
||||||
|
extend(Axis, superClass);
|
||||||
|
|
||||||
|
function Axis() {
|
||||||
|
return Axis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Axis.prototype.default_view = AxisView;
|
||||||
|
|
||||||
|
Axis.prototype.type = 'Axis';
|
||||||
|
|
||||||
|
Axis.mixins(['line:axis_', 'line:major_tick_', 'line:minor_tick_', 'text:major_label_', 'text:axis_label_']);
|
||||||
|
|
||||||
|
Axis.define({
|
||||||
|
bounds: [p.Any, 'auto'],
|
||||||
|
ticker: [p.Instance, null],
|
||||||
|
formatter: [p.Instance, null],
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default'],
|
||||||
|
axis_label: [p.String, ''],
|
||||||
|
axis_label_standoff: [p.Int, 5],
|
||||||
|
major_label_standoff: [p.Int, 5],
|
||||||
|
major_label_orientation: [p.Any, "horizontal"],
|
||||||
|
major_tick_in: [p.Number, 2],
|
||||||
|
major_tick_out: [p.Number, 6],
|
||||||
|
minor_tick_in: [p.Number, 0],
|
||||||
|
minor_tick_out: [p.Number, 4]
|
||||||
|
});
|
||||||
|
|
||||||
|
Axis.override({
|
||||||
|
axis_line_color: 'black',
|
||||||
|
major_tick_line_color: 'black',
|
||||||
|
minor_tick_line_color: 'black',
|
||||||
|
major_label_text_font_size: "8pt",
|
||||||
|
major_label_text_align: "center",
|
||||||
|
major_label_text_baseline: "alphabetic",
|
||||||
|
axis_label_text_font_size: "10pt",
|
||||||
|
axis_label_text_font_style: "italic"
|
||||||
|
});
|
||||||
|
|
||||||
|
Axis.internal({
|
||||||
|
panel_side: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
Axis.prototype.initialize = function(attrs, options) {
|
||||||
|
Axis.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.define_computed_property('computed_bounds', this._computed_bounds, false);
|
||||||
|
this.add_dependencies('computed_bounds', this, ['bounds']);
|
||||||
|
this.add_dependencies('computed_bounds', this.get('plot'), ['x_range', 'y_range']);
|
||||||
|
this.define_computed_property('rule_coords', this._rule_coords, false);
|
||||||
|
this.add_dependencies('rule_coords', this, ['computed_bounds', 'side']);
|
||||||
|
this.define_computed_property('tick_coords', this._tick_coords, false);
|
||||||
|
this.add_dependencies('tick_coords', this, ['computed_bounds', 'panel_side']);
|
||||||
|
this.define_computed_property('ranges', this._ranges, true);
|
||||||
|
this.define_computed_property('normals', (function() {
|
||||||
|
return this.panel._normals;
|
||||||
|
}), true);
|
||||||
|
this.define_computed_property('dimension', (function() {
|
||||||
|
return this.panel._dim;
|
||||||
|
}), true);
|
||||||
|
return this.define_computed_property('offsets', this._offsets, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype.add_panel = function(side) {
|
||||||
|
this.panel = new SidePanel.Model({
|
||||||
|
side: side
|
||||||
|
});
|
||||||
|
this.panel.attach_document(this.document);
|
||||||
|
return this.set('panel_side', side);
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._offsets = function() {
|
||||||
|
var frame, ref, side, xoff, yoff;
|
||||||
|
side = this.get('panel_side');
|
||||||
|
ref = [0, 0], xoff = ref[0], yoff = ref[1];
|
||||||
|
frame = this.plot.plot_canvas.get('frame');
|
||||||
|
if (side === "below") {
|
||||||
|
yoff = Math.abs(this.panel.get("top") - frame.get("bottom"));
|
||||||
|
} else if (side === "above") {
|
||||||
|
yoff = Math.abs(this.panel.get("bottom") - frame.get("top"));
|
||||||
|
} else if (side === "right") {
|
||||||
|
xoff = Math.abs(this.panel.get("left") - frame.get("right"));
|
||||||
|
} else if (side === "left") {
|
||||||
|
xoff = Math.abs(this.panel.get("right") - frame.get("left"));
|
||||||
|
}
|
||||||
|
return [xoff, yoff];
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._ranges = function() {
|
||||||
|
var frame, i, j, ranges;
|
||||||
|
i = this.get('dimension');
|
||||||
|
j = (i + 1) % 2;
|
||||||
|
frame = this.plot.plot_canvas.get('frame');
|
||||||
|
ranges = [frame.get('x_ranges')[this.get('x_range_name')], frame.get('y_ranges')[this.get('y_range_name')]];
|
||||||
|
return [ranges[i], ranges[j]];
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._computed_bounds = function() {
|
||||||
|
var cross_range, end, range, range_bounds, ref, ref1, start, user_bounds;
|
||||||
|
ref = this.get('ranges'), range = ref[0], cross_range = ref[1];
|
||||||
|
user_bounds = (ref1 = this.get('bounds')) != null ? ref1 : 'auto';
|
||||||
|
range_bounds = [range.get('min'), range.get('max')];
|
||||||
|
if (user_bounds === 'auto') {
|
||||||
|
return range_bounds;
|
||||||
|
}
|
||||||
|
if (_.isArray(user_bounds)) {
|
||||||
|
if (Math.abs(user_bounds[0] - user_bounds[1]) > Math.abs(range_bounds[0] - range_bounds[1])) {
|
||||||
|
start = Math.max(Math.min(user_bounds[0], user_bounds[1]), range_bounds[0]);
|
||||||
|
end = Math.min(Math.max(user_bounds[0], user_bounds[1]), range_bounds[1]);
|
||||||
|
} else {
|
||||||
|
start = Math.min(user_bounds[0], user_bounds[1]);
|
||||||
|
end = Math.max(user_bounds[0], user_bounds[1]);
|
||||||
|
}
|
||||||
|
return [start, end];
|
||||||
|
}
|
||||||
|
logger.error("user bounds '" + user_bounds + "' not understood");
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._rule_coords = function() {
|
||||||
|
var coords, cross_range, end, i, j, loc, range, ref, ref1, start, xs, ys;
|
||||||
|
i = this.get('dimension');
|
||||||
|
j = (i + 1) % 2;
|
||||||
|
ref = this.get('ranges'), range = ref[0], cross_range = ref[1];
|
||||||
|
ref1 = this.get('computed_bounds'), start = ref1[0], end = ref1[1];
|
||||||
|
xs = new Array(2);
|
||||||
|
ys = new Array(2);
|
||||||
|
coords = [xs, ys];
|
||||||
|
loc = this._get_loc(cross_range);
|
||||||
|
coords[i][0] = Math.max(start, range.get('min'));
|
||||||
|
coords[i][1] = Math.min(end, range.get('max'));
|
||||||
|
if (coords[i][0] > coords[i][1]) {
|
||||||
|
coords[i][0] = coords[i][1] = NaN;
|
||||||
|
}
|
||||||
|
coords[j][0] = loc;
|
||||||
|
coords[j][1] = loc;
|
||||||
|
return coords;
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._tick_coords = function() {
|
||||||
|
var coords, cross_range, end, i, ii, j, k, l, loc, m, majors, minor_coords, minor_xs, minor_ys, minors, range, range_max, range_min, ref, ref1, ref2, ref3, ref4, ref5, start, ticks, xs, ys;
|
||||||
|
i = this.get('dimension');
|
||||||
|
j = (i + 1) % 2;
|
||||||
|
ref = this.get('ranges'), range = ref[0], cross_range = ref[1];
|
||||||
|
ref1 = this.get('computed_bounds'), start = ref1[0], end = ref1[1];
|
||||||
|
ticks = this.get('ticker').get_ticks(start, end, range, {});
|
||||||
|
majors = ticks.major;
|
||||||
|
minors = ticks.minor;
|
||||||
|
loc = this._get_loc(cross_range);
|
||||||
|
xs = [];
|
||||||
|
ys = [];
|
||||||
|
coords = [xs, ys];
|
||||||
|
minor_xs = [];
|
||||||
|
minor_ys = [];
|
||||||
|
minor_coords = [minor_xs, minor_ys];
|
||||||
|
if (range.type === "FactorRange") {
|
||||||
|
for (ii = k = 0, ref2 = majors.length; 0 <= ref2 ? k < ref2 : k > ref2; ii = 0 <= ref2 ? ++k : --k) {
|
||||||
|
coords[i].push(majors[ii]);
|
||||||
|
coords[j].push(loc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ref3 = [range.get('min'), range.get('max')], range_min = ref3[0], range_max = ref3[1];
|
||||||
|
for (ii = l = 0, ref4 = majors.length; 0 <= ref4 ? l < ref4 : l > ref4; ii = 0 <= ref4 ? ++l : --l) {
|
||||||
|
if (majors[ii] < range_min || majors[ii] > range_max) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
coords[i].push(majors[ii]);
|
||||||
|
coords[j].push(loc);
|
||||||
|
}
|
||||||
|
for (ii = m = 0, ref5 = minors.length; 0 <= ref5 ? m < ref5 : m > ref5; ii = 0 <= ref5 ? ++m : --m) {
|
||||||
|
if (minors[ii] < range_min || minors[ii] > range_max) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
minor_coords[i].push(minors[ii]);
|
||||||
|
minor_coords[j].push(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"major": coords,
|
||||||
|
"minor": minor_coords
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis.prototype._get_loc = function(cross_range) {
|
||||||
|
var cend, cstart, loc, side;
|
||||||
|
cstart = cross_range.get('start');
|
||||||
|
cend = cross_range.get('end');
|
||||||
|
side = this.get('panel_side');
|
||||||
|
if (side === 'left' || side === 'below') {
|
||||||
|
loc = 'start';
|
||||||
|
} else if (side === 'right' || side === 'above') {
|
||||||
|
loc = 'end';
|
||||||
|
}
|
||||||
|
return cross_range.get(loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Axis;
|
||||||
|
|
||||||
|
})(GuideRenderer.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Axis,
|
||||||
|
View: AxisView
|
||||||
|
};
|
|
@ -0,0 +1,64 @@
|
||||||
|
var Axis, CategoricalAxis, CategoricalAxisView, CategoricalTickFormatter, CategoricalTicker, _, logger,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Axis = require("./axis");
|
||||||
|
|
||||||
|
CategoricalTickFormatter = require("../formatters/categorical_tick_formatter");
|
||||||
|
|
||||||
|
CategoricalTicker = require("../tickers/categorical_ticker");
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
CategoricalAxisView = (function(superClass) {
|
||||||
|
extend(CategoricalAxisView, superClass);
|
||||||
|
|
||||||
|
function CategoricalAxisView() {
|
||||||
|
return CategoricalAxisView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CategoricalAxisView;
|
||||||
|
|
||||||
|
})(Axis.View);
|
||||||
|
|
||||||
|
CategoricalAxis = (function(superClass) {
|
||||||
|
extend(CategoricalAxis, superClass);
|
||||||
|
|
||||||
|
function CategoricalAxis() {
|
||||||
|
return CategoricalAxis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoricalAxis.prototype.default_view = CategoricalAxisView;
|
||||||
|
|
||||||
|
CategoricalAxis.prototype.type = 'CategoricalAxis';
|
||||||
|
|
||||||
|
CategoricalAxis.override({
|
||||||
|
ticker: function() {
|
||||||
|
return new CategoricalTicker.Model();
|
||||||
|
},
|
||||||
|
formatter: function() {
|
||||||
|
return new CategoricalTickFormatter.Model();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CategoricalAxis.prototype._computed_bounds = function() {
|
||||||
|
var cross_range, range, range_bounds, ref, ref1, user_bounds;
|
||||||
|
ref = this.get('ranges'), range = ref[0], cross_range = ref[1];
|
||||||
|
user_bounds = (ref1 = this.get('bounds')) != null ? ref1 : 'auto';
|
||||||
|
range_bounds = [range.get('min'), range.get('max')];
|
||||||
|
if (user_bounds !== 'auto') {
|
||||||
|
logger.warn("Categorical Axes only support user_bounds='auto', ignoring");
|
||||||
|
}
|
||||||
|
return range_bounds;
|
||||||
|
};
|
||||||
|
|
||||||
|
return CategoricalAxis;
|
||||||
|
|
||||||
|
})(Axis.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: CategoricalAxis,
|
||||||
|
View: CategoricalAxisView
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
var Axis, ContinuousAxis,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
Axis = require("./axis");
|
||||||
|
|
||||||
|
ContinuousAxis = (function(superClass) {
|
||||||
|
extend(ContinuousAxis, superClass);
|
||||||
|
|
||||||
|
function ContinuousAxis() {
|
||||||
|
return ContinuousAxis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContinuousAxis.prototype.type = 'ContinuousAxis';
|
||||||
|
|
||||||
|
return ContinuousAxis;
|
||||||
|
|
||||||
|
})(Axis.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: ContinuousAxis
|
||||||
|
};
|
|
@ -0,0 +1,51 @@
|
||||||
|
var DatetimeAxis, DatetimeAxisView, DatetimeTickFormatter, DatetimeTicker, LinearAxis, _,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
LinearAxis = require("./axis");
|
||||||
|
|
||||||
|
DatetimeTickFormatter = require("../formatters/datetime_tick_formatter");
|
||||||
|
|
||||||
|
DatetimeTicker = require("../tickers/datetime_ticker");
|
||||||
|
|
||||||
|
DatetimeAxisView = (function(superClass) {
|
||||||
|
extend(DatetimeAxisView, superClass);
|
||||||
|
|
||||||
|
function DatetimeAxisView() {
|
||||||
|
return DatetimeAxisView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DatetimeAxisView;
|
||||||
|
|
||||||
|
})(LinearAxis.View);
|
||||||
|
|
||||||
|
DatetimeAxis = (function(superClass) {
|
||||||
|
extend(DatetimeAxis, superClass);
|
||||||
|
|
||||||
|
function DatetimeAxis() {
|
||||||
|
return DatetimeAxis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatetimeAxis.prototype.default_view = DatetimeAxisView;
|
||||||
|
|
||||||
|
DatetimeAxis.prototype.type = 'DatetimeAxis';
|
||||||
|
|
||||||
|
DatetimeAxis.override({
|
||||||
|
ticker: function() {
|
||||||
|
return new DatetimeTicker.Model();
|
||||||
|
},
|
||||||
|
formatter: function() {
|
||||||
|
return new DatetimeTickFormatter.Model();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return DatetimeAxis;
|
||||||
|
|
||||||
|
})(LinearAxis.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: DatetimeAxis,
|
||||||
|
View: DatetimeAxisView
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
var Axis, BasicTickFormatter, BasicTicker, ContinuousAxis, LinearAxis, LinearAxisView, _,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Axis = require("./axis");
|
||||||
|
|
||||||
|
ContinuousAxis = require("./continuous_axis");
|
||||||
|
|
||||||
|
BasicTickFormatter = require("../formatters/basic_tick_formatter");
|
||||||
|
|
||||||
|
BasicTicker = require("../tickers/basic_ticker");
|
||||||
|
|
||||||
|
LinearAxisView = (function(superClass) {
|
||||||
|
extend(LinearAxisView, superClass);
|
||||||
|
|
||||||
|
function LinearAxisView() {
|
||||||
|
return LinearAxisView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LinearAxisView;
|
||||||
|
|
||||||
|
})(Axis.View);
|
||||||
|
|
||||||
|
LinearAxis = (function(superClass) {
|
||||||
|
extend(LinearAxis, superClass);
|
||||||
|
|
||||||
|
function LinearAxis() {
|
||||||
|
return LinearAxis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearAxis.prototype.default_view = LinearAxisView;
|
||||||
|
|
||||||
|
LinearAxis.prototype.type = 'LinearAxis';
|
||||||
|
|
||||||
|
LinearAxis.override({
|
||||||
|
ticker: function() {
|
||||||
|
return new BasicTicker.Model();
|
||||||
|
},
|
||||||
|
formatter: function() {
|
||||||
|
return new BasicTickFormatter.Model();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return LinearAxis;
|
||||||
|
|
||||||
|
})(ContinuousAxis.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: LinearAxis,
|
||||||
|
View: LinearAxisView
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
var Axis, ContinuousAxis, LogAxis, LogAxisView, LogTickFormatter, LogTicker, _,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Axis = require("./axis");
|
||||||
|
|
||||||
|
ContinuousAxis = require("./continuous_axis");
|
||||||
|
|
||||||
|
LogTickFormatter = require("../formatters/log_tick_formatter");
|
||||||
|
|
||||||
|
LogTicker = require("../tickers/log_ticker");
|
||||||
|
|
||||||
|
LogAxisView = (function(superClass) {
|
||||||
|
extend(LogAxisView, superClass);
|
||||||
|
|
||||||
|
function LogAxisView() {
|
||||||
|
return LogAxisView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LogAxisView;
|
||||||
|
|
||||||
|
})(Axis.View);
|
||||||
|
|
||||||
|
LogAxis = (function(superClass) {
|
||||||
|
extend(LogAxis, superClass);
|
||||||
|
|
||||||
|
function LogAxis() {
|
||||||
|
return LogAxis.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogAxis.prototype.default_view = LogAxisView;
|
||||||
|
|
||||||
|
LogAxis.prototype.type = 'LogAxis';
|
||||||
|
|
||||||
|
LogAxis.override({
|
||||||
|
ticker: function() {
|
||||||
|
return new LogTicker.Model();
|
||||||
|
},
|
||||||
|
formatter: function() {
|
||||||
|
return new LogTickFormatter.Model();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return LogAxis;
|
||||||
|
|
||||||
|
})(ContinuousAxis.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: LogAxis,
|
||||||
|
View: LogAxisView
|
||||||
|
};
|
|
@ -0,0 +1,71 @@
|
||||||
|
var CustomJS, Model, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty,
|
||||||
|
slice = [].slice;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Model = require("../../model");
|
||||||
|
|
||||||
|
CustomJS = (function(superClass) {
|
||||||
|
extend(CustomJS, superClass);
|
||||||
|
|
||||||
|
function CustomJS() {
|
||||||
|
return CustomJS.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomJS.prototype.type = 'CustomJS';
|
||||||
|
|
||||||
|
CustomJS.define({
|
||||||
|
args: [p.Any, {}],
|
||||||
|
code: [p.String, ''],
|
||||||
|
lang: [p.String, 'javascript']
|
||||||
|
});
|
||||||
|
|
||||||
|
CustomJS.prototype.initialize = function(attrs, options) {
|
||||||
|
CustomJS.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.define_computed_property('values', this._make_values, true);
|
||||||
|
this.add_dependencies('values', this, ['args']);
|
||||||
|
this.define_computed_property('func', this._make_func, true);
|
||||||
|
return this.add_dependencies('func', this, ['args', 'code']);
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomJS.prototype.execute = function(cb_obj, cb_data) {
|
||||||
|
return this.get('func').apply(null, slice.call(this.get('values')).concat([cb_obj], [cb_data], [require]));
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomJS.prototype._make_values = function() {
|
||||||
|
return _.values(this.get("args"));
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomJS.prototype._make_func = function() {
|
||||||
|
var code, coffee;
|
||||||
|
code = this.get("code");
|
||||||
|
code = (function() {
|
||||||
|
switch (this.get("lang")) {
|
||||||
|
case "javascript":
|
||||||
|
return code;
|
||||||
|
case "coffeescript":
|
||||||
|
coffee = require("coffee-script");
|
||||||
|
return coffee.compile(code, {
|
||||||
|
bare: true,
|
||||||
|
shiftLine: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).call(this);
|
||||||
|
return (function(func, args, ctor) {
|
||||||
|
ctor.prototype = func.prototype;
|
||||||
|
var child = new ctor, result = func.apply(child, args);
|
||||||
|
return Object(result) === result ? result : child;
|
||||||
|
})(Function, slice.call(_.keys(this.get("args"))).concat(["cb_obj"], ["cb_data"], ["require"], [code]), function(){});
|
||||||
|
};
|
||||||
|
|
||||||
|
return CustomJS;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: CustomJS
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
var Model, OpenURL, Util, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Model = require("../../model");
|
||||||
|
|
||||||
|
Util = require("../../util/util");
|
||||||
|
|
||||||
|
OpenURL = (function(superClass) {
|
||||||
|
extend(OpenURL, superClass);
|
||||||
|
|
||||||
|
function OpenURL() {
|
||||||
|
return OpenURL.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenURL.prototype.type = 'OpenURL';
|
||||||
|
|
||||||
|
OpenURL.define({
|
||||||
|
url: [p.String, 'http://']
|
||||||
|
});
|
||||||
|
|
||||||
|
OpenURL.prototype.execute = function(data_source) {
|
||||||
|
var i, j, len, ref, url;
|
||||||
|
ref = Util.get_indices(data_source);
|
||||||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||||||
|
i = ref[j];
|
||||||
|
url = Util.replace_placeholders(this.get("url"), data_source, i);
|
||||||
|
window.open(url);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return OpenURL;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: OpenURL
|
||||||
|
};
|
|
@ -0,0 +1,225 @@
|
||||||
|
var BokehView, Canvas, CanvasView, EQ, GE, LayoutCanvas, _, canvas_template, fixup_ellipse, fixup_image_smoothing, fixup_line_dash, fixup_line_dash_offset, fixup_measure_text, get_scale_ratio, logger, p, ref, ref1,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
canvas_template = require("./canvas_template");
|
||||||
|
|
||||||
|
LayoutCanvas = require("../../core/layout/layout_canvas");
|
||||||
|
|
||||||
|
BokehView = require("../../core/bokeh_view");
|
||||||
|
|
||||||
|
ref = require("../../core/layout/solver"), GE = ref.GE, EQ = ref.EQ;
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
ref1 = require("../../core/util/canvas"), fixup_image_smoothing = ref1.fixup_image_smoothing, fixup_line_dash = ref1.fixup_line_dash, fixup_line_dash_offset = ref1.fixup_line_dash_offset, fixup_measure_text = ref1.fixup_measure_text, get_scale_ratio = ref1.get_scale_ratio, fixup_ellipse = ref1.fixup_ellipse;
|
||||||
|
|
||||||
|
CanvasView = (function(superClass) {
|
||||||
|
extend(CanvasView, superClass);
|
||||||
|
|
||||||
|
function CanvasView() {
|
||||||
|
return CanvasView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CanvasView.prototype.className = "bk-canvas-wrapper";
|
||||||
|
|
||||||
|
CanvasView.prototype.template = canvas_template;
|
||||||
|
|
||||||
|
CanvasView.prototype.initialize = function(options) {
|
||||||
|
var html, ref2;
|
||||||
|
CanvasView.__super__.initialize.call(this, options);
|
||||||
|
html = this.template({
|
||||||
|
map: this.mget('map')
|
||||||
|
});
|
||||||
|
this.$el.html(html);
|
||||||
|
this.ctx = this.get_ctx();
|
||||||
|
this.ctx.glcanvas = null;
|
||||||
|
fixup_line_dash(this.ctx);
|
||||||
|
fixup_line_dash_offset(this.ctx);
|
||||||
|
fixup_image_smoothing(this.ctx);
|
||||||
|
fixup_measure_text(this.ctx);
|
||||||
|
fixup_ellipse(this.ctx);
|
||||||
|
this.map_div = (ref2 = this.$('div.bk-canvas-map')) != null ? ref2 : null;
|
||||||
|
this.set_dims([this.model.initial_width, this.model.initial_height]);
|
||||||
|
return logger.debug("CanvasView initialized");
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasView.prototype.get_canvas_element = function() {
|
||||||
|
return this.$('canvas.bk-canvas')[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasView.prototype.get_ctx = function() {
|
||||||
|
var canvas_el, ctx;
|
||||||
|
canvas_el = this.$('canvas.bk-canvas');
|
||||||
|
ctx = canvas_el[0].getContext('2d');
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasView.prototype.prepare_canvas = function(force) {
|
||||||
|
var canvas_el, dpr, height, ratio, width;
|
||||||
|
if (force == null) {
|
||||||
|
force = false;
|
||||||
|
}
|
||||||
|
width = this.model._width._value;
|
||||||
|
height = this.model._height._value;
|
||||||
|
dpr = window.devicePixelRatio;
|
||||||
|
if (!_.isEqual(this.last_dims, [width, height, dpr]) || force) {
|
||||||
|
this.$el.css({
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
});
|
||||||
|
this.pixel_ratio = ratio = get_scale_ratio(this.ctx, this.mget('use_hidpi'));
|
||||||
|
canvas_el = this.$('.bk-canvas');
|
||||||
|
canvas_el.css({
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
});
|
||||||
|
canvas_el.attr('width', width * ratio);
|
||||||
|
canvas_el.attr('height', height * ratio);
|
||||||
|
logger.debug("Rendering CanvasView [force=" + force + "] with width: " + width + ", height: " + height + ", ratio: " + ratio);
|
||||||
|
this.model.pixel_ratio = this.pixel_ratio;
|
||||||
|
return this.last_dims = [width, height, dpr];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasView.prototype.set_dims = function(dims, trigger) {
|
||||||
|
if (trigger == null) {
|
||||||
|
trigger = true;
|
||||||
|
}
|
||||||
|
this.requested_width = dims[0];
|
||||||
|
this.requested_height = dims[1];
|
||||||
|
this.update_constraints(trigger);
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasView.prototype.update_constraints = function(trigger) {
|
||||||
|
var MIN_SIZE, requested_height, requested_width, s;
|
||||||
|
if (trigger == null) {
|
||||||
|
trigger = true;
|
||||||
|
}
|
||||||
|
requested_width = this.requested_width;
|
||||||
|
requested_height = this.requested_height;
|
||||||
|
if ((requested_width == null) || (requested_height == null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MIN_SIZE = 50;
|
||||||
|
if (requested_width < MIN_SIZE || requested_height < MIN_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_.isEqual(this.last_requested_dims, [requested_width, requested_height])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = this.model.document.solver();
|
||||||
|
if (this._width_constraint != null) {
|
||||||
|
s.remove_constraint(this._width_constraint);
|
||||||
|
}
|
||||||
|
this._width_constraint = EQ(this.model._width, -requested_width);
|
||||||
|
s.add_constraint(this._width_constraint);
|
||||||
|
if (this._height_constraint != null) {
|
||||||
|
s.remove_constraint(this._height_constraint);
|
||||||
|
}
|
||||||
|
this._height_constraint = EQ(this.model._height, -requested_height);
|
||||||
|
s.add_constraint(this._height_constraint);
|
||||||
|
this.last_requested_dims = [requested_width, requested_height];
|
||||||
|
return s.update_variables(trigger);
|
||||||
|
};
|
||||||
|
|
||||||
|
return CanvasView;
|
||||||
|
|
||||||
|
})(BokehView);
|
||||||
|
|
||||||
|
Canvas = (function(superClass) {
|
||||||
|
extend(Canvas, superClass);
|
||||||
|
|
||||||
|
function Canvas() {
|
||||||
|
return Canvas.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas.prototype.type = 'Canvas';
|
||||||
|
|
||||||
|
Canvas.prototype.default_view = CanvasView;
|
||||||
|
|
||||||
|
Canvas.internal({
|
||||||
|
map: [p.Boolean, false],
|
||||||
|
initial_width: [p.Number],
|
||||||
|
initial_height: [p.Number],
|
||||||
|
use_hidpi: [p.Boolean, true],
|
||||||
|
pixel_ratio: [p.Number]
|
||||||
|
});
|
||||||
|
|
||||||
|
Canvas.prototype.initialize = function(attrs, options) {
|
||||||
|
Canvas.__super__.initialize.call(this, attrs, options);
|
||||||
|
return this.panel = this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.vx_to_sx = function(x) {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.vy_to_sy = function(y) {
|
||||||
|
return this._height._value - (y + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.v_vx_to_sx = function(xx) {
|
||||||
|
return new Float64Array(xx);
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.v_vy_to_sy = function(yy) {
|
||||||
|
var _yy, height, i, idx, len, y;
|
||||||
|
_yy = new Float64Array(yy.length);
|
||||||
|
height = this._height._value;
|
||||||
|
for (idx = i = 0, len = yy.length; i < len; idx = ++i) {
|
||||||
|
y = yy[idx];
|
||||||
|
_yy[idx] = height - (y + 1);
|
||||||
|
}
|
||||||
|
return _yy;
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.sx_to_vx = function(x) {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.sy_to_vy = function(y) {
|
||||||
|
return this._height._value - (y + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.v_sx_to_vx = function(xx) {
|
||||||
|
return new Float64Array(xx);
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.v_sy_to_vy = function(yy) {
|
||||||
|
var _yy, height, i, idx, len, y;
|
||||||
|
_yy = new Float64Array(yy.length);
|
||||||
|
height = this._height._value;
|
||||||
|
for (idx = i = 0, len = yy.length; i < len; idx = ++i) {
|
||||||
|
y = yy[idx];
|
||||||
|
_yy[idx] = height - (y + 1);
|
||||||
|
}
|
||||||
|
return _yy;
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.prototype.get_constraints = function() {
|
||||||
|
var constraints;
|
||||||
|
constraints = Canvas.__super__.get_constraints.call(this);
|
||||||
|
constraints.push(GE(this._top));
|
||||||
|
constraints.push(GE(this._bottom));
|
||||||
|
constraints.push(GE(this._left));
|
||||||
|
constraints.push(GE(this._right));
|
||||||
|
constraints.push(GE(this._width));
|
||||||
|
constraints.push(GE(this._height));
|
||||||
|
constraints.push(EQ(this._width, [-1, this._right]));
|
||||||
|
constraints.push(EQ(this._height, [-1, this._top]));
|
||||||
|
return constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Canvas;
|
||||||
|
|
||||||
|
})(LayoutCanvas.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Canvas,
|
||||||
|
View: CanvasView
|
||||||
|
};
|
|
@ -0,0 +1,50 @@
|
||||||
|
module.exports = function(__obj) {
|
||||||
|
if (!__obj) __obj = {};
|
||||||
|
var __out = [];
|
||||||
|
var __capture = function(callback) {
|
||||||
|
var out = __out, result;
|
||||||
|
__out = [];
|
||||||
|
callback.call(this);
|
||||||
|
result = __out.join('');
|
||||||
|
__out = out;
|
||||||
|
return __safe(result);
|
||||||
|
};
|
||||||
|
var __sanitize = function(value) {
|
||||||
|
if (value && value.ecoSafe) {
|
||||||
|
return value;
|
||||||
|
} else if (typeof value !== 'undefined' && value != null) {
|
||||||
|
return __escape(value);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __safe = function(value) {
|
||||||
|
if (value && value.ecoSafe) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
if (!(typeof value !== 'undefined' && value != null)) value = '';
|
||||||
|
var result = new String(value);
|
||||||
|
result.ecoSafe = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __escape = function(value) {
|
||||||
|
return ('' + value)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"');
|
||||||
|
};
|
||||||
|
(function() {
|
||||||
|
(function() {
|
||||||
|
if (this.map) {
|
||||||
|
__out.push('\n<div class="bk-canvas-map"></div>\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
__out.push('\n<div class="bk-canvas-events" />\n<div class="bk-canvas-overlays" />\n<canvas class=\'bk-canvas\'></canvas>');
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
}).call(__obj);
|
||||||
|
return __out.join('');
|
||||||
|
};
|
|
@ -0,0 +1,194 @@
|
||||||
|
var CartesianFrame, CategoricalMapper, EQ, GE, GridMapper, LayoutCanvas, LinearMapper, LogMapper, Range1d, _, logging, p, ref,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
CategoricalMapper = require("../mappers/categorical_mapper");
|
||||||
|
|
||||||
|
GridMapper = require("../mappers/grid_mapper");
|
||||||
|
|
||||||
|
LinearMapper = require("../mappers/linear_mapper");
|
||||||
|
|
||||||
|
LogMapper = require("../mappers/log_mapper");
|
||||||
|
|
||||||
|
Range1d = require("../ranges/range1d");
|
||||||
|
|
||||||
|
ref = require("../../core/layout/solver"), EQ = ref.EQ, GE = ref.GE;
|
||||||
|
|
||||||
|
LayoutCanvas = require("../../core/layout/layout_canvas");
|
||||||
|
|
||||||
|
logging = require("../../core/logging").logging;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
CartesianFrame = (function(superClass) {
|
||||||
|
extend(CartesianFrame, superClass);
|
||||||
|
|
||||||
|
function CartesianFrame() {
|
||||||
|
return CartesianFrame.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CartesianFrame.prototype.type = 'CartesianFrame';
|
||||||
|
|
||||||
|
CartesianFrame.prototype.initialize = function(attrs, options) {
|
||||||
|
CartesianFrame.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.panel = this;
|
||||||
|
this.define_computed_property('x_ranges', function() {
|
||||||
|
return this._get_ranges('x');
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('x_ranges', this, ['x_range', 'extra_x_ranges']);
|
||||||
|
this.define_computed_property('y_ranges', function() {
|
||||||
|
return this._get_ranges('y');
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('y_ranges', this, ['y_range', 'extra_y_ranges']);
|
||||||
|
this.define_computed_property('x_mappers', function() {
|
||||||
|
return this._get_mappers('x', this.get('x_ranges'), this.get('h_range'));
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('x_ranges', this, ['x_ranges', 'h_range']);
|
||||||
|
this.define_computed_property('y_mappers', function() {
|
||||||
|
return this._get_mappers('y', this.get('y_ranges'), this.get('v_range'));
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('y_ranges', this, ['y_ranges', 'v_range']);
|
||||||
|
this.define_computed_property('mapper', function() {
|
||||||
|
return new GridMapper.Model({
|
||||||
|
domain_mapper: this.get('x_mapper'),
|
||||||
|
codomain_mapper: this.get('y_mapper')
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('mapper', this, ['x_mapper', 'y_mapper']);
|
||||||
|
this._h_range = new Range1d.Model({
|
||||||
|
start: this.get('left'),
|
||||||
|
end: this.get('left') + this.get('width')
|
||||||
|
});
|
||||||
|
this.define_computed_property('h_range', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
_this._h_range.set('start', _this.get('left'));
|
||||||
|
_this._h_range.set('end', _this.get('left') + _this.get('width'));
|
||||||
|
return _this._h_range;
|
||||||
|
};
|
||||||
|
})(this), false);
|
||||||
|
this.add_dependencies('h_range', this, ['left', 'width']);
|
||||||
|
this._v_range = new Range1d.Model({
|
||||||
|
start: this.get('bottom'),
|
||||||
|
end: this.get('bottom') + this.get('height')
|
||||||
|
});
|
||||||
|
this.define_computed_property('v_range', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
_this._v_range.set('start', _this.get('bottom'));
|
||||||
|
_this._v_range.set('end', _this.get('bottom') + _this.get('height'));
|
||||||
|
return _this._v_range;
|
||||||
|
};
|
||||||
|
})(this), false);
|
||||||
|
this.add_dependencies('v_range', this, ['bottom', 'height']);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype._doc_attached = function() {
|
||||||
|
this.listenTo(this.document.solver(), 'layout_update', this._update_mappers);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype.contains = function(vx, vy) {
|
||||||
|
return vx >= this.get('left') && vx <= this.get('right') && vy >= this.get('bottom') && vy <= this.get('top');
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype.map_to_screen = function(x, y, canvas, x_name, y_name) {
|
||||||
|
var sx, sy, vx, vy;
|
||||||
|
if (x_name == null) {
|
||||||
|
x_name = 'default';
|
||||||
|
}
|
||||||
|
if (y_name == null) {
|
||||||
|
y_name = 'default';
|
||||||
|
}
|
||||||
|
vx = this.get('x_mappers')[x_name].v_map_to_target(x);
|
||||||
|
sx = canvas.v_vx_to_sx(vx);
|
||||||
|
vy = this.get('y_mappers')[y_name].v_map_to_target(y);
|
||||||
|
sy = canvas.v_vy_to_sy(vy);
|
||||||
|
return [sx, sy];
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype._get_ranges = function(dim) {
|
||||||
|
var extra_ranges, name, range, ranges;
|
||||||
|
ranges = {};
|
||||||
|
ranges['default'] = this.get(dim + "_range");
|
||||||
|
extra_ranges = this.get("extra_" + dim + "_ranges");
|
||||||
|
if (extra_ranges != null) {
|
||||||
|
for (name in extra_ranges) {
|
||||||
|
range = extra_ranges[name];
|
||||||
|
ranges[name] = range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype._get_mappers = function(dim, ranges, frame_range) {
|
||||||
|
var mapper_type, mappers, name, range;
|
||||||
|
mappers = {};
|
||||||
|
for (name in ranges) {
|
||||||
|
range = ranges[name];
|
||||||
|
if (range.type === "Range1d" || range.type === "DataRange1d") {
|
||||||
|
if (this.get(dim + "_mapper_type") === "log") {
|
||||||
|
mapper_type = LogMapper.Model;
|
||||||
|
} else {
|
||||||
|
mapper_type = LinearMapper.Model;
|
||||||
|
}
|
||||||
|
} else if (range.type === "FactorRange") {
|
||||||
|
mapper_type = CategoricalMapper.Model;
|
||||||
|
} else {
|
||||||
|
logger.warn("unknown range type for range '" + name + "': " + range);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
mappers[name] = new mapper_type({
|
||||||
|
source_range: range,
|
||||||
|
target_range: frame_range
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return mappers;
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.prototype._update_mappers = function() {
|
||||||
|
var mapper, name, ref1, ref2;
|
||||||
|
ref1 = this.get('x_mappers');
|
||||||
|
for (name in ref1) {
|
||||||
|
mapper = ref1[name];
|
||||||
|
mapper.set('target_range', this.get('h_range'));
|
||||||
|
}
|
||||||
|
ref2 = this.get('y_mappers');
|
||||||
|
for (name in ref2) {
|
||||||
|
mapper = ref2[name];
|
||||||
|
mapper.set('target_range', this.get('v_range'));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
CartesianFrame.internal({
|
||||||
|
extra_x_ranges: [p.Any, {}],
|
||||||
|
extra_y_ranges: [p.Any, {}],
|
||||||
|
x_range: [p.Instance],
|
||||||
|
y_range: [p.Instance],
|
||||||
|
x_mapper_type: [p.Any],
|
||||||
|
y_mapper_type: [p.Any]
|
||||||
|
});
|
||||||
|
|
||||||
|
CartesianFrame.prototype.get_constraints = function() {
|
||||||
|
var constraints;
|
||||||
|
constraints = [];
|
||||||
|
constraints.push(GE(this._top));
|
||||||
|
constraints.push(GE(this._bottom));
|
||||||
|
constraints.push(GE(this._left));
|
||||||
|
constraints.push(GE(this._right));
|
||||||
|
constraints.push(GE(this._width));
|
||||||
|
constraints.push(GE(this._height));
|
||||||
|
constraints.push(EQ(this._left, this._width, [-1, this._right]));
|
||||||
|
constraints.push(EQ(this._bottom, this._height, [-1, this._top]));
|
||||||
|
return constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
return CartesianFrame;
|
||||||
|
|
||||||
|
})(LayoutCanvas.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: CartesianFrame
|
||||||
|
};
|
|
@ -0,0 +1,119 @@
|
||||||
|
var BasicTickFormatter, TickFormatter, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
TickFormatter = require("./tick_formatter");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
BasicTickFormatter = (function(superClass) {
|
||||||
|
extend(BasicTickFormatter, superClass);
|
||||||
|
|
||||||
|
function BasicTickFormatter() {
|
||||||
|
return BasicTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicTickFormatter.prototype.type = 'BasicTickFormatter';
|
||||||
|
|
||||||
|
BasicTickFormatter.define({
|
||||||
|
precision: [p.Any, 'auto'],
|
||||||
|
use_scientific: [p.Bool, true],
|
||||||
|
power_limit_high: [p.Number, 5],
|
||||||
|
power_limit_low: [p.Number, -3]
|
||||||
|
});
|
||||||
|
|
||||||
|
BasicTickFormatter.prototype.initialize = function(attrs, options) {
|
||||||
|
BasicTickFormatter.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.define_computed_property('scientific_limit_low', function() {
|
||||||
|
return Math.pow(10.0, this.get('power_limit_low'));
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('scientific_limit_low', this, ['power_limit_low']);
|
||||||
|
this.define_computed_property('scientific_limit_high', function() {
|
||||||
|
return Math.pow(10.0, this.get('power_limit_high'));
|
||||||
|
}, true);
|
||||||
|
this.add_dependencies('scientific_limit_high', this, ['power_limit_high']);
|
||||||
|
return this.last_precision = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
BasicTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
var i, is_ok, j, k, l, labels, len, m, n, need_sci, o, precision, ref, ref1, ref2, ref3, ref4, tick, tick_abs, x, zero_eps;
|
||||||
|
if (ticks.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
zero_eps = 0;
|
||||||
|
if (ticks.length >= 2) {
|
||||||
|
zero_eps = Math.abs(ticks[1] - ticks[0]) / 10000;
|
||||||
|
}
|
||||||
|
need_sci = false;
|
||||||
|
if (this.get('use_scientific')) {
|
||||||
|
for (j = 0, len = ticks.length; j < len; j++) {
|
||||||
|
tick = ticks[j];
|
||||||
|
tick_abs = Math.abs(tick);
|
||||||
|
if (tick_abs > zero_eps && (tick_abs >= this.get('scientific_limit_high') || tick_abs <= this.get('scientific_limit_low'))) {
|
||||||
|
need_sci = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
precision = this.get('precision');
|
||||||
|
if ((precision == null) || _.isNumber(precision)) {
|
||||||
|
labels = new Array(ticks.length);
|
||||||
|
if (need_sci) {
|
||||||
|
for (i = k = 0, ref = ticks.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
|
||||||
|
labels[i] = ticks[i].toExponential(precision || void 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = l = 0, ref1 = ticks.length; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
|
||||||
|
labels[i] = ticks[i].toFixed(precision || void 0).replace(/(\.[0-9]*?)0+$/, "$1").replace(/\.$/, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
} else if (precision === 'auto') {
|
||||||
|
labels = new Array(ticks.length);
|
||||||
|
for (x = m = ref2 = this.last_precision; ref2 <= 15 ? m <= 15 : m >= 15; x = ref2 <= 15 ? ++m : --m) {
|
||||||
|
is_ok = true;
|
||||||
|
if (need_sci) {
|
||||||
|
for (i = n = 0, ref3 = ticks.length; 0 <= ref3 ? n < ref3 : n > ref3; i = 0 <= ref3 ? ++n : --n) {
|
||||||
|
labels[i] = ticks[i].toExponential(x);
|
||||||
|
if (i > 0) {
|
||||||
|
if (labels[i] === labels[i - 1]) {
|
||||||
|
is_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = o = 0, ref4 = ticks.length; 0 <= ref4 ? o < ref4 : o > ref4; i = 0 <= ref4 ? ++o : --o) {
|
||||||
|
labels[i] = ticks[i].toFixed(x).replace(/(\.[0-9]*?)0+$/, "$1").replace(/\.$/, "");
|
||||||
|
if (i > 0) {
|
||||||
|
if (labels[i] === labels[i - 1]) {
|
||||||
|
is_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_ok) {
|
||||||
|
this.last_precision = x;
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
return BasicTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: BasicTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
var CategoricalTickFormatter, TickFormatter,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
TickFormatter = require("../formatters/tick_formatter");
|
||||||
|
|
||||||
|
CategoricalTickFormatter = (function(superClass) {
|
||||||
|
extend(CategoricalTickFormatter, superClass);
|
||||||
|
|
||||||
|
function CategoricalTickFormatter() {
|
||||||
|
return CategoricalTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoricalTickFormatter.prototype.type = 'CategoricalTickFormatter';
|
||||||
|
|
||||||
|
CategoricalTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
return ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
return CategoricalTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: CategoricalTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,234 @@
|
||||||
|
var DEFAULT_DATETIME_FORMATS, DatetimeTickFormatter, SPrintf, TickFormatter, _, _array, _strftime, _us, logger, p, tz,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
SPrintf = require("sprintf");
|
||||||
|
|
||||||
|
tz = require("timezone");
|
||||||
|
|
||||||
|
TickFormatter = require("./tick_formatter");
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
_us = function(t) {
|
||||||
|
return Math.round(((t / 1000) % 1) * 1000000);
|
||||||
|
};
|
||||||
|
|
||||||
|
_array = function(t) {
|
||||||
|
return tz(t, "%Y %m %d %H %M %S").split(/\s+/).map(function(e) {
|
||||||
|
return parseInt(e, 10);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_strftime = function(t, format) {
|
||||||
|
var microsecond_replacement_string;
|
||||||
|
if (_.isFunction(format)) {
|
||||||
|
return format(t);
|
||||||
|
} else {
|
||||||
|
microsecond_replacement_string = SPrintf.sprintf("$1%06d", _us(t));
|
||||||
|
format = format.replace(/((^|[^%])(%%)*)%f/, microsecond_replacement_string);
|
||||||
|
if (format.indexOf("%") === -1) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
return tz(t, format);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFAULT_DATETIME_FORMATS = {
|
||||||
|
'microseconds': ['%fus'],
|
||||||
|
'milliseconds': ['%3Nms', '%S.%3Ns'],
|
||||||
|
'seconds': ['%Ss'],
|
||||||
|
'minsec': [':%M:%S'],
|
||||||
|
'minutes': [':%M', '%Mm'],
|
||||||
|
'hourmin': ['%H:%M'],
|
||||||
|
'hours': ['%Hh', '%H:%M'],
|
||||||
|
'days': ['%m/%d', '%a%d'],
|
||||||
|
'months': ['%m/%Y', '%b%y'],
|
||||||
|
'years': ['%Y']
|
||||||
|
};
|
||||||
|
|
||||||
|
DatetimeTickFormatter = (function(superClass) {
|
||||||
|
extend(DatetimeTickFormatter, superClass);
|
||||||
|
|
||||||
|
function DatetimeTickFormatter() {
|
||||||
|
return DatetimeTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype.type = 'DatetimeTickFormatter';
|
||||||
|
|
||||||
|
DatetimeTickFormatter.define({
|
||||||
|
formats: [p.Any, DEFAULT_DATETIME_FORMATS]
|
||||||
|
});
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype.format_order = ['microseconds', 'milliseconds', 'seconds', 'minsec', 'minutes', 'hourmin', 'hours', 'days', 'months', 'years'];
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype.strip_leading_zeros = true;
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype.initialize = function(attrs, options) {
|
||||||
|
DatetimeTickFormatter.__super__.initialize.call(this, attrs, options);
|
||||||
|
return this._update_width_formats();
|
||||||
|
};
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype._update_width_formats = function() {
|
||||||
|
var fmt_name, fmt_string, fmt_strings, now, ref, results, sizes, sorted;
|
||||||
|
now = tz(new Date());
|
||||||
|
this._width_formats = {};
|
||||||
|
ref = this.formats;
|
||||||
|
results = [];
|
||||||
|
for (fmt_name in ref) {
|
||||||
|
fmt_strings = ref[fmt_name];
|
||||||
|
sizes = (function() {
|
||||||
|
var j, len, results1;
|
||||||
|
results1 = [];
|
||||||
|
for (j = 0, len = fmt_strings.length; j < len; j++) {
|
||||||
|
fmt_string = fmt_strings[j];
|
||||||
|
results1.push(_strftime(now, fmt_string).length);
|
||||||
|
}
|
||||||
|
return results1;
|
||||||
|
})();
|
||||||
|
sorted = _.sortBy(_.zip(sizes, fmt_strings), function(arg) {
|
||||||
|
var fmt, size;
|
||||||
|
size = arg[0], fmt = arg[1];
|
||||||
|
return size;
|
||||||
|
});
|
||||||
|
results.push(this._width_formats[fmt_name] = _.zip.apply(_, sorted));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype._get_resolution_str = function(resolution_secs, span_secs) {
|
||||||
|
var adjusted_resolution_secs, str;
|
||||||
|
adjusted_resolution_secs = resolution_secs * 1.1;
|
||||||
|
if (adjusted_resolution_secs < 1e-3) {
|
||||||
|
str = "microseconds";
|
||||||
|
} else if (adjusted_resolution_secs < 1.0) {
|
||||||
|
str = "milliseconds";
|
||||||
|
} else if (adjusted_resolution_secs < 60) {
|
||||||
|
if (span_secs >= 60) {
|
||||||
|
str = "minsec";
|
||||||
|
} else {
|
||||||
|
str = "seconds";
|
||||||
|
}
|
||||||
|
} else if (adjusted_resolution_secs < 3600) {
|
||||||
|
if (span_secs >= 3600) {
|
||||||
|
str = "hourmin";
|
||||||
|
} else {
|
||||||
|
str = "minutes";
|
||||||
|
}
|
||||||
|
} else if (adjusted_resolution_secs < 24 * 3600) {
|
||||||
|
str = "hours";
|
||||||
|
} else if (adjusted_resolution_secs < 31 * 24 * 3600) {
|
||||||
|
str = "days";
|
||||||
|
} else if (adjusted_resolution_secs < 365 * 24 * 3600) {
|
||||||
|
str = "months";
|
||||||
|
} else {
|
||||||
|
str = "years";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
DatetimeTickFormatter.prototype.doFormat = function(ticks, num_labels, char_width, fill_ratio, ticker) {
|
||||||
|
var error, error1, fmt, format, formats, good_formats, hybrid_handled, i, j, k, l, labels, len, len1, next_format, next_ndx, r, ref, ref1, ref2, resol, resol_ndx, s, span, ss, t, time_tuple_ndx_for_resol, tm, widths;
|
||||||
|
if (num_labels == null) {
|
||||||
|
num_labels = null;
|
||||||
|
}
|
||||||
|
if (char_width == null) {
|
||||||
|
char_width = null;
|
||||||
|
}
|
||||||
|
if (fill_ratio == null) {
|
||||||
|
fill_ratio = 0.3;
|
||||||
|
}
|
||||||
|
if (ticker == null) {
|
||||||
|
ticker = null;
|
||||||
|
}
|
||||||
|
if (ticks.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
span = Math.abs(ticks[ticks.length - 1] - ticks[0]) / 1000.0;
|
||||||
|
if (ticker) {
|
||||||
|
r = ticker.resolution;
|
||||||
|
} else {
|
||||||
|
r = span / (ticks.length - 1);
|
||||||
|
}
|
||||||
|
resol = this._get_resolution_str(r, span);
|
||||||
|
ref = this._width_formats[resol], widths = ref[0], formats = ref[1];
|
||||||
|
format = formats[0];
|
||||||
|
if (char_width) {
|
||||||
|
good_formats = [];
|
||||||
|
for (i = j = 0, ref1 = widths.length; 0 <= ref1 ? j < ref1 : j > ref1; i = 0 <= ref1 ? ++j : --j) {
|
||||||
|
if (widths[i] * ticks.length < fill_ratio * char_width) {
|
||||||
|
good_formats.push(this._width_formats[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (good_formats.length > 0) {
|
||||||
|
format = _.last(good_formats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labels = [];
|
||||||
|
resol_ndx = this.format_order.indexOf(resol);
|
||||||
|
time_tuple_ndx_for_resol = {};
|
||||||
|
ref2 = this.format_order;
|
||||||
|
for (k = 0, len = ref2.length; k < len; k++) {
|
||||||
|
fmt = ref2[k];
|
||||||
|
time_tuple_ndx_for_resol[fmt] = 0;
|
||||||
|
}
|
||||||
|
time_tuple_ndx_for_resol["seconds"] = 5;
|
||||||
|
time_tuple_ndx_for_resol["minsec"] = 4;
|
||||||
|
time_tuple_ndx_for_resol["minutes"] = 4;
|
||||||
|
time_tuple_ndx_for_resol["hourmin"] = 3;
|
||||||
|
time_tuple_ndx_for_resol["hours"] = 3;
|
||||||
|
for (l = 0, len1 = ticks.length; l < len1; l++) {
|
||||||
|
t = ticks[l];
|
||||||
|
try {
|
||||||
|
tm = _array(t);
|
||||||
|
s = _strftime(t, format);
|
||||||
|
} catch (error1) {
|
||||||
|
error = error1;
|
||||||
|
logger.warn("unable to format tick for timestamp value " + t);
|
||||||
|
logger.warn(" - " + error);
|
||||||
|
labels.push("ERR");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
hybrid_handled = false;
|
||||||
|
next_ndx = resol_ndx;
|
||||||
|
while (tm[time_tuple_ndx_for_resol[this.format_order[next_ndx]]] === 0) {
|
||||||
|
next_ndx += 1;
|
||||||
|
if (next_ndx === this.format_order.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((resol === "minsec" || resol === "hourmin") && !hybrid_handled) {
|
||||||
|
if ((resol === "minsec" && tm[4] === 0 && tm[5] !== 0) || (resol === "hourmin" && tm[3] === 0 && tm[4] !== 0)) {
|
||||||
|
next_format = this._width_formats[this.format_order[resol_ndx - 1]][1][0];
|
||||||
|
s = _strftime(t, next_format);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
hybrid_handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_format = this._width_formats[this.format_order[next_ndx]][1][0];
|
||||||
|
s = _strftime(t, next_format);
|
||||||
|
}
|
||||||
|
if (this.strip_leading_zeros) {
|
||||||
|
ss = s.replace(/^0+/g, "");
|
||||||
|
if (ss !== s && isNaN(parseInt(ss))) {
|
||||||
|
ss = '0' + ss;
|
||||||
|
}
|
||||||
|
labels.push(ss);
|
||||||
|
} else {
|
||||||
|
labels.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
return DatetimeTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: DatetimeTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,50 @@
|
||||||
|
var FuncTickFormatter, TickFormatter, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
TickFormatter = require("../formatters/tick_formatter");
|
||||||
|
|
||||||
|
FuncTickFormatter = (function(superClass) {
|
||||||
|
extend(FuncTickFormatter, superClass);
|
||||||
|
|
||||||
|
function FuncTickFormatter() {
|
||||||
|
return FuncTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncTickFormatter.prototype.type = 'FuncTickFormatter';
|
||||||
|
|
||||||
|
FuncTickFormatter.define({
|
||||||
|
code: [p.String, ''],
|
||||||
|
lang: [p.String, 'javascript']
|
||||||
|
});
|
||||||
|
|
||||||
|
FuncTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
var code, coffee, func;
|
||||||
|
code = this.get("code");
|
||||||
|
code = (function() {
|
||||||
|
switch (this.get("lang")) {
|
||||||
|
case "javascript":
|
||||||
|
return code;
|
||||||
|
case "coffeescript":
|
||||||
|
coffee = require("coffee-script");
|
||||||
|
return coffee.compile(code, {
|
||||||
|
bare: true,
|
||||||
|
shiftLine: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).call(this);
|
||||||
|
func = new Function("tick", "var func = " + code + "return func(tick)");
|
||||||
|
return _.map(ticks, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
return FuncTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: FuncTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,67 @@
|
||||||
|
var BasicTickFormatter, LogTickFormatter, TickFormatter, _, logger, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
BasicTickFormatter = require("./basic_tick_formatter");
|
||||||
|
|
||||||
|
TickFormatter = require("./tick_formatter");
|
||||||
|
|
||||||
|
logger = require("../../core/logging").logger;
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
LogTickFormatter = (function(superClass) {
|
||||||
|
extend(LogTickFormatter, superClass);
|
||||||
|
|
||||||
|
function LogTickFormatter() {
|
||||||
|
return LogTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTickFormatter.prototype.type = 'LogTickFormatter';
|
||||||
|
|
||||||
|
LogTickFormatter.define({
|
||||||
|
ticker: [p.Instance, null]
|
||||||
|
});
|
||||||
|
|
||||||
|
LogTickFormatter.prototype.initialize = function(attrs, options) {
|
||||||
|
LogTickFormatter.__super__.initialize.call(this, attrs, options);
|
||||||
|
this.basic_formatter = new BasicTickFormatter.Model();
|
||||||
|
if (this.get('ticker') == null) {
|
||||||
|
return logger.warn("LogTickFormatter not configured with a ticker, using default base of 10 (labels will be incorrect if ticker base is not 10)");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LogTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
var base, i, j, labels, ref, small_interval;
|
||||||
|
if (ticks.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (this.get('ticker') != null) {
|
||||||
|
base = this.get('ticker').get('base');
|
||||||
|
} else {
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
small_interval = false;
|
||||||
|
labels = new Array(ticks.length);
|
||||||
|
for (i = j = 0, ref = ticks.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
labels[i] = base + "^" + (Math.round(Math.log(ticks[i]) / Math.log(base)));
|
||||||
|
if ((i > 0) && (labels[i] === labels[i - 1])) {
|
||||||
|
small_interval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (small_interval) {
|
||||||
|
labels = this.basic_formatter.doFormat(ticks);
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
return LogTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: LogTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,63 @@
|
||||||
|
var Numbro, NumeralTickFormatter, TickFormatter, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Numbro = require("numbro");
|
||||||
|
|
||||||
|
TickFormatter = require("./tick_formatter");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
NumeralTickFormatter = (function(superClass) {
|
||||||
|
extend(NumeralTickFormatter, superClass);
|
||||||
|
|
||||||
|
function NumeralTickFormatter() {
|
||||||
|
return NumeralTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumeralTickFormatter.prototype.type = 'NumeralTickFormatter';
|
||||||
|
|
||||||
|
NumeralTickFormatter.define({
|
||||||
|
format: [p.String, '0,0'],
|
||||||
|
language: [p.String, 'en'],
|
||||||
|
rounding: [p.String, 'round']
|
||||||
|
});
|
||||||
|
|
||||||
|
NumeralTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
var format, labels, language, rounding, tick;
|
||||||
|
format = this.get("format");
|
||||||
|
language = this.get("language");
|
||||||
|
rounding = (function() {
|
||||||
|
switch (this.get("rounding")) {
|
||||||
|
case "round":
|
||||||
|
case "nearest":
|
||||||
|
return Math.round;
|
||||||
|
case "floor":
|
||||||
|
case "rounddown":
|
||||||
|
return Math.floor;
|
||||||
|
case "ceil":
|
||||||
|
case "roundup":
|
||||||
|
return Math.ceil;
|
||||||
|
}
|
||||||
|
}).call(this);
|
||||||
|
labels = (function() {
|
||||||
|
var i, len, results;
|
||||||
|
results = [];
|
||||||
|
for (i = 0, len = ticks.length; i < len; i++) {
|
||||||
|
tick = ticks[i];
|
||||||
|
results.push(Numbro.format(tick, format, language, rounding));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
return labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
return NumeralTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: NumeralTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,47 @@
|
||||||
|
var PrintfTickFormatter, SPrintf, TickFormatter, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
SPrintf = require("sprintf");
|
||||||
|
|
||||||
|
TickFormatter = require("./tick_formatter");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
PrintfTickFormatter = (function(superClass) {
|
||||||
|
extend(PrintfTickFormatter, superClass);
|
||||||
|
|
||||||
|
function PrintfTickFormatter() {
|
||||||
|
return PrintfTickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintfTickFormatter.prototype.type = 'PrintfTickFormatter';
|
||||||
|
|
||||||
|
PrintfTickFormatter.define({
|
||||||
|
format: [p.String, '%s']
|
||||||
|
});
|
||||||
|
|
||||||
|
PrintfTickFormatter.prototype.doFormat = function(ticks) {
|
||||||
|
var format, labels, tick;
|
||||||
|
format = this.get("format");
|
||||||
|
labels = (function() {
|
||||||
|
var i, len, results;
|
||||||
|
results = [];
|
||||||
|
for (i = 0, len = ticks.length; i < len; i++) {
|
||||||
|
tick = ticks[i];
|
||||||
|
results.push(SPrintf.sprintf(format, tick));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
return labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
return PrintfTickFormatter;
|
||||||
|
|
||||||
|
})(TickFormatter.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: PrintfTickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
var Model, TickFormatter, _,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Model = require("../../model");
|
||||||
|
|
||||||
|
TickFormatter = (function(superClass) {
|
||||||
|
extend(TickFormatter, superClass);
|
||||||
|
|
||||||
|
function TickFormatter() {
|
||||||
|
return TickFormatter.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
TickFormatter.prototype.type = 'TickFormatter';
|
||||||
|
|
||||||
|
TickFormatter.prototype.doFormat = function(ticks) {};
|
||||||
|
|
||||||
|
return TickFormatter;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: TickFormatter
|
||||||
|
};
|
|
@ -0,0 +1,200 @@
|
||||||
|
var AnnularWedge, AnnularWedgeView, Glyph, _, angle_between, hittest, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
hittest = require("../../common/hittest");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
angle_between = require("../../core/util/math").angle_between;
|
||||||
|
|
||||||
|
AnnularWedgeView = (function(superClass) {
|
||||||
|
extend(AnnularWedgeView, superClass);
|
||||||
|
|
||||||
|
function AnnularWedgeView() {
|
||||||
|
return AnnularWedgeView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype._map_data = function() {
|
||||||
|
var i, j, ref, results;
|
||||||
|
if (this.model.properties.inner_radius.units === "data") {
|
||||||
|
this.sinner_radius = this.sdist(this.renderer.xmapper, this._x, this._inner_radius);
|
||||||
|
} else {
|
||||||
|
this.sinner_radius = this._inner_radius;
|
||||||
|
}
|
||||||
|
if (this.model.properties.outer_radius.units === "data") {
|
||||||
|
this.souter_radius = this.sdist(this.renderer.xmapper, this._x, this._outer_radius);
|
||||||
|
} else {
|
||||||
|
this.souter_radius = this._outer_radius;
|
||||||
|
}
|
||||||
|
this._angle = new Float32Array(this._start_angle.length);
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = this._start_angle.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(this._angle[i] = this._end_angle[i] - this._start_angle[i]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var _angle, _start_angle, direction, i, j, len, results, sinner_radius, souter_radius, sx, sy;
|
||||||
|
sx = arg.sx, sy = arg.sy, _start_angle = arg._start_angle, _angle = arg._angle, sinner_radius = arg.sinner_radius, souter_radius = arg.souter_radius;
|
||||||
|
direction = this.model.properties.direction.value();
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sx[i] + sy[i] + sinner_radius[i] + souter_radius[i] + _start_angle[i] + _angle[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.translate(sx[i], sy[i]);
|
||||||
|
ctx.rotate(_start_angle[i]);
|
||||||
|
ctx.moveTo(souter_radius[i], 0);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(0, 0, souter_radius[i], 0, _angle[i], direction);
|
||||||
|
ctx.rotate(_angle[i]);
|
||||||
|
ctx.lineTo(sinner_radius[i], 0);
|
||||||
|
ctx.arc(0, 0, sinner_radius[i], 0, -_angle[i], !direction);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.rotate(-_angle[i] - _start_angle[i]);
|
||||||
|
ctx.translate(-sx[i], -sy[i]);
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype._hit_point = function(geometry) {
|
||||||
|
var angle, bbox, candidates, direction, dist, hits, i, ir2, j, k, len, len1, or2, pt, ref, ref1, ref2, ref3, ref4, result, sx, sx0, sx1, sy, sy0, sy1, vx, vx0, vx1, vy, vy0, vy1, x, x0, x1, y, y0, y1;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
x = this.renderer.xmapper.map_from_target(vx, true);
|
||||||
|
y = this.renderer.ymapper.map_from_target(vy, true);
|
||||||
|
if (this.model.properties.outer_radius.units === "data") {
|
||||||
|
x0 = x - this.max_outer_radius;
|
||||||
|
x1 = x + this.max_outer_radius;
|
||||||
|
y0 = y - this.max_outer_radius;
|
||||||
|
y1 = y + this.max_outer_radius;
|
||||||
|
} else {
|
||||||
|
vx0 = vx - this.max_outer_radius;
|
||||||
|
vx1 = vx + this.max_outer_radius;
|
||||||
|
ref1 = this.renderer.xmapper.v_map_from_target([vx0, vx1], true), x0 = ref1[0], x1 = ref1[1];
|
||||||
|
vy0 = vy - this.max_outer_radius;
|
||||||
|
vy1 = vy + this.max_outer_radius;
|
||||||
|
ref2 = this.renderer.ymapper.v_map_from_target([vy0, vy1], true), y0 = ref2[0], y1 = ref2[1];
|
||||||
|
}
|
||||||
|
candidates = [];
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
ref3 = (function() {
|
||||||
|
var k, len, ref3, results;
|
||||||
|
ref3 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (k = 0, len = ref3.length; k < len; k++) {
|
||||||
|
pt = ref3[k];
|
||||||
|
results.push(pt.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
for (j = 0, len = ref3.length; j < len; j++) {
|
||||||
|
i = ref3[j];
|
||||||
|
or2 = Math.pow(this.souter_radius[i], 2);
|
||||||
|
ir2 = Math.pow(this.sinner_radius[i], 2);
|
||||||
|
sx0 = this.renderer.xmapper.map_to_target(x, true);
|
||||||
|
sx1 = this.renderer.xmapper.map_to_target(this._x[i], true);
|
||||||
|
sy0 = this.renderer.ymapper.map_to_target(y, true);
|
||||||
|
sy1 = this.renderer.ymapper.map_to_target(this._y[i], true);
|
||||||
|
dist = Math.pow(sx0 - sx1, 2) + Math.pow(sy0 - sy1, 2);
|
||||||
|
if (dist <= or2 && dist >= ir2) {
|
||||||
|
candidates.push([i, dist]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction = this.model.properties.direction.value();
|
||||||
|
hits = [];
|
||||||
|
for (k = 0, len1 = candidates.length; k < len1; k++) {
|
||||||
|
ref4 = candidates[k], i = ref4[0], dist = ref4[1];
|
||||||
|
sx = this.renderer.plot_view.canvas.vx_to_sx(vx);
|
||||||
|
sy = this.renderer.plot_view.canvas.vy_to_sy(vy);
|
||||||
|
angle = Math.atan2(sy - this.sy[i], sx - this.sx[i]);
|
||||||
|
if (angle_between(-angle, -this._start_angle[i], -this._end_angle[i], direction)) {
|
||||||
|
hits.push([i, dist]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = _.chain(hits).sortBy(function(elt) {
|
||||||
|
return elt[1];
|
||||||
|
}).map(function(elt) {
|
||||||
|
return elt[0];
|
||||||
|
}).value();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
return this._generic_area_legend(ctx, x0, x1, y0, y1);
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype._scxy = function(i) {
|
||||||
|
var a, r;
|
||||||
|
r = (this.sinner_radius[i] + this.souter_radius[i]) / 2;
|
||||||
|
a = (this._start_angle[i] + this._end_angle[i]) / 2;
|
||||||
|
return {
|
||||||
|
x: this.sx[i] + r * Math.cos(a),
|
||||||
|
y: this.sy[i] + r * Math.sin(a)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype.scx = function(i) {
|
||||||
|
return this._scxy(i).x;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnularWedgeView.prototype.scy = function(i) {
|
||||||
|
return this._scxy(i).y;
|
||||||
|
};
|
||||||
|
|
||||||
|
return AnnularWedgeView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
AnnularWedge = (function(superClass) {
|
||||||
|
extend(AnnularWedge, superClass);
|
||||||
|
|
||||||
|
function AnnularWedge() {
|
||||||
|
return AnnularWedge.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnularWedge.prototype.default_view = AnnularWedgeView;
|
||||||
|
|
||||||
|
AnnularWedge.prototype.type = 'AnnularWedge';
|
||||||
|
|
||||||
|
AnnularWedge.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
AnnularWedge.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
AnnularWedge.define({
|
||||||
|
direction: [p.Direction, 'anticlock'],
|
||||||
|
inner_radius: [p.DistanceSpec],
|
||||||
|
outer_radius: [p.DistanceSpec],
|
||||||
|
start_angle: [p.AngleSpec],
|
||||||
|
end_angle: [p.AngleSpec]
|
||||||
|
});
|
||||||
|
|
||||||
|
return AnnularWedge;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: AnnularWedge,
|
||||||
|
View: AnnularWedgeView
|
||||||
|
};
|
|
@ -0,0 +1,173 @@
|
||||||
|
var Annulus, AnnulusView, Glyph, _, hittest, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
hittest = require("../../common/hittest");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
AnnulusView = (function(superClass) {
|
||||||
|
extend(AnnulusView, superClass);
|
||||||
|
|
||||||
|
function AnnulusView() {
|
||||||
|
return AnnulusView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnulusView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnulusView.prototype._map_data = function() {
|
||||||
|
if (this.model.properties.inner_radius.units === "data") {
|
||||||
|
this.sinner_radius = this.sdist(this.renderer.xmapper, this._x, this._inner_radius);
|
||||||
|
} else {
|
||||||
|
this.sinner_radius = this._inner_radius;
|
||||||
|
}
|
||||||
|
if (this.model.properties.outer_radius.units === "data") {
|
||||||
|
return this.souter_radius = this.sdist(this.renderer.xmapper, this._x, this._outer_radius);
|
||||||
|
} else {
|
||||||
|
return this.souter_radius = this._outer_radius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnulusView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var clockwise, i, isie, j, k, len, len1, ref, results, sinner_radius, souter_radius, sx, sy;
|
||||||
|
sx = arg.sx, sy = arg.sy, sinner_radius = arg.sinner_radius, souter_radius = arg.souter_radius;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sx[i] + sy[i] + sinner_radius[i] + souter_radius[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
isie = navigator.userAgent.indexOf('MSIE') >= 0 || navigator.userAgent.indexOf('Trident') > 0 || navigator.userAgent.indexOf('Edge') > 0;
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
if (isie) {
|
||||||
|
ref = [false, true];
|
||||||
|
for (k = 0, len1 = ref.length; k < len1; k++) {
|
||||||
|
clockwise = ref[k];
|
||||||
|
ctx.arc(sx[i], sy[i], sinner_radius[i], 0, Math.PI, clockwise);
|
||||||
|
ctx.arc(sx[i], sy[i], souter_radius[i], Math.PI, 0, !clockwise);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.arc(sx[i], sy[i], sinner_radius[i], 0, 2 * Math.PI, true);
|
||||||
|
ctx.arc(sx[i], sy[i], souter_radius[i], 2 * Math.PI, 0, false);
|
||||||
|
}
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(sx[i], sy[i], sinner_radius[i], 0, 2 * Math.PI);
|
||||||
|
ctx.moveTo(sx[i] + souter_radius[i], sy[i]);
|
||||||
|
ctx.arc(sx[i], sy[i], souter_radius[i], 0, 2 * Math.PI);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnulusView.prototype._hit_point = function(geometry) {
|
||||||
|
var bbox, dist, hits, i, ir2, j, len, or2, pt, ref, ref1, result, sx0, sx1, sy0, sy1, vx, vy, x, x0, x1, y, y0, y1;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
x = this.renderer.xmapper.map_from_target(vx, true);
|
||||||
|
x0 = x - this.max_radius;
|
||||||
|
x1 = x + this.max_radius;
|
||||||
|
y = this.renderer.ymapper.map_from_target(vy, true);
|
||||||
|
y0 = y - this.max_radius;
|
||||||
|
y1 = y + this.max_radius;
|
||||||
|
hits = [];
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
ref1 = (function() {
|
||||||
|
var k, len, ref1, results;
|
||||||
|
ref1 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (k = 0, len = ref1.length; k < len; k++) {
|
||||||
|
pt = ref1[k];
|
||||||
|
results.push(pt.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
for (j = 0, len = ref1.length; j < len; j++) {
|
||||||
|
i = ref1[j];
|
||||||
|
or2 = Math.pow(this.souter_radius[i], 2);
|
||||||
|
ir2 = Math.pow(this.sinner_radius[i], 2);
|
||||||
|
sx0 = this.renderer.xmapper.map_to_target(x);
|
||||||
|
sx1 = this.renderer.xmapper.map_to_target(this._x[i]);
|
||||||
|
sy0 = this.renderer.ymapper.map_to_target(y);
|
||||||
|
sy1 = this.renderer.ymapper.map_to_target(this._y[i]);
|
||||||
|
dist = Math.pow(sx0 - sx1, 2) + Math.pow(sy0 - sy1, 2);
|
||||||
|
if (dist <= or2 && dist >= ir2) {
|
||||||
|
hits.push([i, dist]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = _.chain(hits).sortBy(function(elt) {
|
||||||
|
return elt[1];
|
||||||
|
}).map(function(elt) {
|
||||||
|
return elt[0];
|
||||||
|
}).value();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnulusView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
var data, indices, r, ref, reference_point, sinner_radius, souter_radius, sx, sy;
|
||||||
|
reference_point = (ref = this.get_reference_point()) != null ? ref : 0;
|
||||||
|
indices = [reference_point];
|
||||||
|
sx = {};
|
||||||
|
sx[reference_point] = (x0 + x1) / 2;
|
||||||
|
sy = {};
|
||||||
|
sy[reference_point] = (y0 + y1) / 2;
|
||||||
|
r = Math.min(Math.abs(x1 - x0), Math.abs(y1 - y0)) * 0.5;
|
||||||
|
sinner_radius = {};
|
||||||
|
sinner_radius[reference_point] = r * 0.4;
|
||||||
|
souter_radius = {};
|
||||||
|
souter_radius[reference_point] = r * 0.8;
|
||||||
|
data = {
|
||||||
|
sx: sx,
|
||||||
|
sy: sy,
|
||||||
|
sinner_radius: sinner_radius,
|
||||||
|
souter_radius: souter_radius
|
||||||
|
};
|
||||||
|
return this._render(ctx, indices, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return AnnulusView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Annulus = (function(superClass) {
|
||||||
|
extend(Annulus, superClass);
|
||||||
|
|
||||||
|
function Annulus() {
|
||||||
|
return Annulus.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Annulus.prototype.default_view = AnnulusView;
|
||||||
|
|
||||||
|
Annulus.prototype.type = 'Annulus';
|
||||||
|
|
||||||
|
Annulus.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Annulus.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
Annulus.define({
|
||||||
|
inner_radius: [p.DistanceSpec],
|
||||||
|
outer_radius: [p.DistanceSpec]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Annulus;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Annulus,
|
||||||
|
View: AnnulusView
|
||||||
|
};
|
|
@ -0,0 +1,87 @@
|
||||||
|
var Arc, ArcView, Glyph, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
ArcView = (function(superClass) {
|
||||||
|
extend(ArcView, superClass);
|
||||||
|
|
||||||
|
function ArcView() {
|
||||||
|
return ArcView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArcView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
ArcView.prototype._map_data = function() {
|
||||||
|
if (this.model.properties.radius.units === "data") {
|
||||||
|
return this.sradius = this.sdist(this.renderer.xmapper, this._x, this._radius);
|
||||||
|
} else {
|
||||||
|
return this.sradius = this._radius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ArcView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var _end_angle, _start_angle, direction, i, j, len, results, sradius, sx, sy;
|
||||||
|
sx = arg.sx, sy = arg.sy, sradius = arg.sradius, _start_angle = arg._start_angle, _end_angle = arg._end_angle;
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
direction = this.model.properties.direction.value();
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sx[i] + sy[i] + sradius[i] + _start_angle[i] + _end_angle[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(sx[i], sy[i], sradius[i], _start_angle[i], _end_angle[i], direction);
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ArcView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
return this._generic_line_legend(ctx, x0, x1, y0, y1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ArcView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Arc = (function(superClass) {
|
||||||
|
extend(Arc, superClass);
|
||||||
|
|
||||||
|
function Arc() {
|
||||||
|
return Arc.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc.prototype.default_view = ArcView;
|
||||||
|
|
||||||
|
Arc.prototype.type = 'Arc';
|
||||||
|
|
||||||
|
Arc.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Arc.mixins(['line']);
|
||||||
|
|
||||||
|
Arc.define({
|
||||||
|
direction: [p.Direction, 'anticlock'],
|
||||||
|
radius: [p.DistanceSpec],
|
||||||
|
start_angle: [p.AngleSpec],
|
||||||
|
end_angle: [p.AngleSpec]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Arc;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Arc,
|
||||||
|
View: ArcView
|
||||||
|
};
|
|
@ -0,0 +1,144 @@
|
||||||
|
var Bezier, BezierView, Glyph, _, _cbb, rbush,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
rbush = require("rbush");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
_cbb = function(x0, y0, x1, y1, x2, y2, x3, y3) {
|
||||||
|
var a, b, b2ac, bounds, c, i, j, jlen, k, mt, sqrtb2ac, t, t1, t2, tvalues, x, y;
|
||||||
|
tvalues = [];
|
||||||
|
bounds = [[], []];
|
||||||
|
for (i = k = 0; k <= 2; i = ++k) {
|
||||||
|
if (i === 0) {
|
||||||
|
b = 6 * x0 - 12 * x1 + 6 * x2;
|
||||||
|
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
|
||||||
|
c = 3 * x1 - 3 * x0;
|
||||||
|
} else {
|
||||||
|
b = 6 * y0 - 12 * y1 + 6 * y2;
|
||||||
|
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
|
||||||
|
c = 3 * y1 - 3 * y0;
|
||||||
|
}
|
||||||
|
if (Math.abs(a) < 1e-12) {
|
||||||
|
if (Math.abs(b) < 1e-12) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t = -c / b;
|
||||||
|
if (0 < t && t < 1) {
|
||||||
|
tvalues.push(t);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
b2ac = b * b - 4 * c * a;
|
||||||
|
sqrtb2ac = Math.sqrt(b2ac);
|
||||||
|
if (b2ac < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t1 = (-b + sqrtb2ac) / (2 * a);
|
||||||
|
if (0 < t1 && t1 < 1) {
|
||||||
|
tvalues.push(t1);
|
||||||
|
}
|
||||||
|
t2 = (-b - sqrtb2ac) / (2 * a);
|
||||||
|
if (0 < t2 && t2 < 1) {
|
||||||
|
tvalues.push(t2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = tvalues.length;
|
||||||
|
jlen = j;
|
||||||
|
while (j--) {
|
||||||
|
t = tvalues[j];
|
||||||
|
mt = 1 - t;
|
||||||
|
x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
|
||||||
|
bounds[0][j] = x;
|
||||||
|
y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
|
||||||
|
bounds[1][j] = y;
|
||||||
|
}
|
||||||
|
bounds[0][jlen] = x0;
|
||||||
|
bounds[1][jlen] = y0;
|
||||||
|
bounds[0][jlen + 1] = x3;
|
||||||
|
bounds[1][jlen + 1] = y3;
|
||||||
|
return [Math.min.apply(null, bounds[0]), Math.max.apply(null, bounds[1]), Math.max.apply(null, bounds[0]), Math.min.apply(null, bounds[1])];
|
||||||
|
};
|
||||||
|
|
||||||
|
BezierView = (function(superClass) {
|
||||||
|
extend(BezierView, superClass);
|
||||||
|
|
||||||
|
function BezierView() {
|
||||||
|
return BezierView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
BezierView.prototype._index_data = function() {
|
||||||
|
var i, index, k, pts, ref, ref1, x0, x1, y0, y1;
|
||||||
|
index = rbush();
|
||||||
|
pts = [];
|
||||||
|
for (i = k = 0, ref = this._x0.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
|
||||||
|
if (isNaN(this._x0[i] + this._x1[i] + this._y0[i] + this._y1[i] + this._cx0[i] + this._cy0[i] + this._cx1[i] + this._cy1[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ref1 = _cbb(this._x0[i], this._y0[i], this._x1[i], this._y1[i], this._cx0[i], this._cy0[i], this._cx1[i], this._cy1[i]), x0 = ref1[0], y0 = ref1[1], x1 = ref1[2], y1 = ref1[3];
|
||||||
|
pts.push({
|
||||||
|
minX: x0,
|
||||||
|
minY: y0,
|
||||||
|
maxX: x1,
|
||||||
|
maxY: y1,
|
||||||
|
i: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
index.load(pts);
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
|
||||||
|
BezierView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var i, k, len, results, scx, scx0, scx1, scy0, scy1, sx0, sx1, sy0, sy1;
|
||||||
|
sx0 = arg.sx0, sy0 = arg.sy0, sx1 = arg.sx1, sy1 = arg.sy1, scx = arg.scx, scx0 = arg.scx0, scy0 = arg.scy0, scx1 = arg.scx1, scy1 = arg.scy1;
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
results = [];
|
||||||
|
for (k = 0, len = indices.length; k < len; k++) {
|
||||||
|
i = indices[k];
|
||||||
|
if (isNaN(sx0[i] + sy0[i] + sx1[i] + sy1[i] + scx0[i] + scy0[i] + scx1[i] + scy1[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(sx0[i], sy0[i]);
|
||||||
|
ctx.bezierCurveTo(scx0[i], scy0[i], scx1[i], scy1[i], sx1[i], sy1[i]);
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BezierView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
return this._generic_line_legend(ctx, x0, x1, y0, y1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return BezierView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Bezier = (function(superClass) {
|
||||||
|
extend(Bezier, superClass);
|
||||||
|
|
||||||
|
function Bezier() {
|
||||||
|
return Bezier.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bezier.prototype.default_view = BezierView;
|
||||||
|
|
||||||
|
Bezier.prototype.type = 'Bezier';
|
||||||
|
|
||||||
|
Bezier.coords([['x0', 'y0'], ['x1', 'y1'], ['cx0', 'cy0'], ['cx1', 'cy1']]);
|
||||||
|
|
||||||
|
Bezier.mixins(['line']);
|
||||||
|
|
||||||
|
return Bezier;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Bezier,
|
||||||
|
View: BezierView
|
||||||
|
};
|
|
@ -0,0 +1,325 @@
|
||||||
|
var Circle, CircleView, Glyph, _, hittest, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
hittest = require("../../common/hittest");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
CircleView = (function(superClass) {
|
||||||
|
extend(CircleView, superClass);
|
||||||
|
|
||||||
|
function CircleView() {
|
||||||
|
return CircleView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CircleView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._map_data = function() {
|
||||||
|
var rd, s;
|
||||||
|
if (this._radius != null) {
|
||||||
|
if (this.model.properties.radius.spec.units === "data") {
|
||||||
|
rd = this.model.properties.radius_dimension.spec.value;
|
||||||
|
return this.sradius = this.sdist(this.renderer[rd + "mapper"], this["_" + rd], this._radius);
|
||||||
|
} else {
|
||||||
|
this.sradius = this._radius;
|
||||||
|
return this.max_size = 2 * this.max_radius;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.sradius = (function() {
|
||||||
|
var j, len, ref, results;
|
||||||
|
ref = this._size;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||||||
|
s = ref[j];
|
||||||
|
results.push(s / 2);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._mask_data = function(all_indices) {
|
||||||
|
var bbox, hr, ref, ref1, ref2, ref3, sx0, sx1, sy0, sy1, vr, x, x0, x1, y0, y1;
|
||||||
|
hr = this.renderer.plot_view.frame.get('h_range');
|
||||||
|
vr = this.renderer.plot_view.frame.get('v_range');
|
||||||
|
if ((this._radius != null) && this.model.properties.radius.units === "data") {
|
||||||
|
sx0 = hr.get('start');
|
||||||
|
sx1 = hr.get('end');
|
||||||
|
ref = this.renderer.xmapper.v_map_from_target([sx0, sx1], true), x0 = ref[0], x1 = ref[1];
|
||||||
|
x0 -= this.max_radius;
|
||||||
|
x1 += this.max_radius;
|
||||||
|
sy0 = vr.get('start');
|
||||||
|
sy1 = vr.get('end');
|
||||||
|
ref1 = this.renderer.ymapper.v_map_from_target([sy0, sy1], true), y0 = ref1[0], y1 = ref1[1];
|
||||||
|
y0 -= this.max_radius;
|
||||||
|
y1 += this.max_radius;
|
||||||
|
} else {
|
||||||
|
sx0 = hr.get('start') - this.max_size;
|
||||||
|
sx1 = hr.get('end') + this.max_size;
|
||||||
|
ref2 = this.renderer.xmapper.v_map_from_target([sx0, sx1], true), x0 = ref2[0], x1 = ref2[1];
|
||||||
|
sy0 = vr.get('start') - this.max_size;
|
||||||
|
sy1 = vr.get('end') + this.max_size;
|
||||||
|
ref3 = this.renderer.ymapper.v_map_from_target([sy0, sy1], true), y0 = ref3[0], y1 = ref3[1];
|
||||||
|
}
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
return (function() {
|
||||||
|
var j, len, ref4, results;
|
||||||
|
ref4 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref4.length; j < len; j++) {
|
||||||
|
x = ref4[j];
|
||||||
|
results.push(x.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var i, j, len, results, sradius, sx, sy;
|
||||||
|
sx = arg.sx, sy = arg.sy, sradius = arg.sradius;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sx[i] + sy[i] + sradius[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(sx[i], sy[i], sradius[i], 0, 2 * Math.PI, false);
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._hit_point = function(geometry) {
|
||||||
|
var bbox, candidates, dist, hits, i, j, k, len, len1, pt, r2, ref, ref1, ref2, ref3, ref4, result, sx, sx0, sx1, sy, sy0, sy1, vx, vx0, vx1, vy, vy0, vy1, x, x0, x1, y, y0, y1;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
x = this.renderer.xmapper.map_from_target(vx, true);
|
||||||
|
y = this.renderer.ymapper.map_from_target(vy, true);
|
||||||
|
if ((this._radius != null) && this.model.properties.radius.units === "data") {
|
||||||
|
x0 = x - this.max_radius;
|
||||||
|
x1 = x + this.max_radius;
|
||||||
|
y0 = y - this.max_radius;
|
||||||
|
y1 = y + this.max_radius;
|
||||||
|
} else {
|
||||||
|
vx0 = vx - this.max_size;
|
||||||
|
vx1 = vx + this.max_size;
|
||||||
|
ref1 = this.renderer.xmapper.v_map_from_target([vx0, vx1], true), x0 = ref1[0], x1 = ref1[1];
|
||||||
|
ref2 = [Math.min(x0, x1), Math.max(x0, x1)], x0 = ref2[0], x1 = ref2[1];
|
||||||
|
vy0 = vy - this.max_size;
|
||||||
|
vy1 = vy + this.max_size;
|
||||||
|
ref3 = this.renderer.ymapper.v_map_from_target([vy0, vy1], true), y0 = ref3[0], y1 = ref3[1];
|
||||||
|
ref4 = [Math.min(y0, y1), Math.max(y0, y1)], y0 = ref4[0], y1 = ref4[1];
|
||||||
|
}
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
candidates = (function() {
|
||||||
|
var j, len, ref5, results;
|
||||||
|
ref5 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref5.length; j < len; j++) {
|
||||||
|
pt = ref5[j];
|
||||||
|
results.push(pt.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
hits = [];
|
||||||
|
if ((this._radius != null) && this.model.properties.radius.units === "data") {
|
||||||
|
for (j = 0, len = candidates.length; j < len; j++) {
|
||||||
|
i = candidates[j];
|
||||||
|
r2 = Math.pow(this.sradius[i], 2);
|
||||||
|
sx0 = this.renderer.xmapper.map_to_target(x, true);
|
||||||
|
sx1 = this.renderer.xmapper.map_to_target(this._x[i], true);
|
||||||
|
sy0 = this.renderer.ymapper.map_to_target(y, true);
|
||||||
|
sy1 = this.renderer.ymapper.map_to_target(this._y[i], true);
|
||||||
|
dist = Math.pow(sx0 - sx1, 2) + Math.pow(sy0 - sy1, 2);
|
||||||
|
if (dist <= r2) {
|
||||||
|
hits.push([i, dist]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sx = this.renderer.plot_view.canvas.vx_to_sx(vx);
|
||||||
|
sy = this.renderer.plot_view.canvas.vy_to_sy(vy);
|
||||||
|
for (k = 0, len1 = candidates.length; k < len1; k++) {
|
||||||
|
i = candidates[k];
|
||||||
|
r2 = Math.pow(this.sradius[i], 2);
|
||||||
|
dist = Math.pow(this.sx[i] - sx, 2) + Math.pow(this.sy[i] - sy, 2);
|
||||||
|
if (dist <= r2) {
|
||||||
|
hits.push([i, dist]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hits = _.chain(hits).sortBy(function(elt) {
|
||||||
|
return elt[1];
|
||||||
|
}).map(function(elt) {
|
||||||
|
return elt[0];
|
||||||
|
}).value();
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = hits;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._hit_span = function(geometry) {
|
||||||
|
var bbox, hits, maxX, maxY, minX, minY, ms, ref, ref1, ref2, ref3, ref4, ref5, result, vx, vx0, vx1, vy, vy0, vy1, x0, x1, xx, y0, y1;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
ref1 = this.bounds(), minX = ref1.minX, minY = ref1.minY, maxX = ref1.maxX, maxY = ref1.maxY;
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
if (geometry.direction === 'h') {
|
||||||
|
y0 = minY;
|
||||||
|
y1 = maxY;
|
||||||
|
if ((this._radius != null) && this.model.properties.radius.units === "data") {
|
||||||
|
vx0 = vx - this.max_radius;
|
||||||
|
vx1 = vx + this.max_radius;
|
||||||
|
ref2 = this.renderer.xmapper.v_map_from_target([vx0, vx1]), x0 = ref2[0], x1 = ref2[1];
|
||||||
|
} else {
|
||||||
|
ms = this.max_size / 2;
|
||||||
|
vx0 = vx - ms;
|
||||||
|
vx1 = vx + ms;
|
||||||
|
ref3 = this.renderer.xmapper.v_map_from_target([vx0, vx1], true), x0 = ref3[0], x1 = ref3[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x0 = minX;
|
||||||
|
x1 = maxX;
|
||||||
|
if ((this._radius != null) && this.model.properties.radius.units === "data") {
|
||||||
|
vy0 = vy - this.max_radius;
|
||||||
|
vy1 = vy + this.max_radius;
|
||||||
|
ref4 = this.renderer.ymapper.v_map_from_target([vy0, vy1]), y0 = ref4[0], y1 = ref4[1];
|
||||||
|
} else {
|
||||||
|
ms = this.max_size / 2;
|
||||||
|
vy0 = vy - ms;
|
||||||
|
vy1 = vy + ms;
|
||||||
|
ref5 = this.renderer.ymapper.v_map_from_target([vy0, vy1], true), y0 = ref5[0], y1 = ref5[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
hits = (function() {
|
||||||
|
var j, len, ref6, results;
|
||||||
|
ref6 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref6.length; j < len; j++) {
|
||||||
|
xx = ref6[j];
|
||||||
|
results.push(xx.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
result['1d'].indices = hits;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._hit_rect = function(geometry) {
|
||||||
|
var bbox, ref, ref1, result, x, x0, x1, y0, y1;
|
||||||
|
ref = this.renderer.xmapper.v_map_from_target([geometry.vx0, geometry.vx1], true), x0 = ref[0], x1 = ref[1];
|
||||||
|
ref1 = this.renderer.ymapper.v_map_from_target([geometry.vy0, geometry.vy1], true), y0 = ref1[0], y1 = ref1[1];
|
||||||
|
bbox = hittest.validate_bbox_coords([x0, x1], [y0, y1]);
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = (function() {
|
||||||
|
var j, len, ref2, results;
|
||||||
|
ref2 = this.index.search(bbox);
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref2.length; j < len; j++) {
|
||||||
|
x = ref2[j];
|
||||||
|
results.push(x.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype._hit_poly = function(geometry) {
|
||||||
|
var candidates, hits, i, idx, j, k, ref, ref1, ref2, result, results, sx, sy, vx, vy;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
sx = this.renderer.plot_view.canvas.v_vx_to_sx(vx);
|
||||||
|
sy = this.renderer.plot_view.canvas.v_vy_to_sy(vy);
|
||||||
|
candidates = (function() {
|
||||||
|
results = [];
|
||||||
|
for (var j = 0, ref1 = this.sx.length; 0 <= ref1 ? j < ref1 : j > ref1; 0 <= ref1 ? j++ : j--){ results.push(j); }
|
||||||
|
return results;
|
||||||
|
}).apply(this);
|
||||||
|
hits = [];
|
||||||
|
for (i = k = 0, ref2 = candidates.length; 0 <= ref2 ? k < ref2 : k > ref2; i = 0 <= ref2 ? ++k : --k) {
|
||||||
|
idx = candidates[i];
|
||||||
|
if (hittest.point_in_poly(this.sx[i], this.sy[i], sx, sy)) {
|
||||||
|
hits.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = hits;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircleView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
var data, indices, ref, reference_point, sradius, sx, sy;
|
||||||
|
reference_point = (ref = this.get_reference_point()) != null ? ref : 0;
|
||||||
|
indices = [reference_point];
|
||||||
|
sx = {};
|
||||||
|
sx[reference_point] = (x0 + x1) / 2;
|
||||||
|
sy = {};
|
||||||
|
sy[reference_point] = (y0 + y1) / 2;
|
||||||
|
sradius = {};
|
||||||
|
sradius[reference_point] = Math.min(Math.abs(x1 - x0), Math.abs(y1 - y0)) * 0.2;
|
||||||
|
data = {
|
||||||
|
sx: sx,
|
||||||
|
sy: sy,
|
||||||
|
sradius: sradius
|
||||||
|
};
|
||||||
|
return this._render(ctx, indices, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return CircleView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Circle = (function(superClass) {
|
||||||
|
extend(Circle, superClass);
|
||||||
|
|
||||||
|
function Circle() {
|
||||||
|
return Circle.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Circle.prototype.default_view = CircleView;
|
||||||
|
|
||||||
|
Circle.prototype.type = 'Circle';
|
||||||
|
|
||||||
|
Circle.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Circle.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
Circle.define({
|
||||||
|
angle: [p.AngleSpec, 0],
|
||||||
|
size: [
|
||||||
|
p.DistanceSpec, {
|
||||||
|
units: "screen",
|
||||||
|
value: 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
radius: [p.DistanceSpec, null],
|
||||||
|
radius_dimension: [p.String, 'x']
|
||||||
|
});
|
||||||
|
|
||||||
|
Circle.prototype.initialize = function(attrs, options) {
|
||||||
|
Circle.__super__.initialize.call(this, attrs, options);
|
||||||
|
return this.properties.radius.optional = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Circle;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Circle,
|
||||||
|
View: CircleView
|
||||||
|
};
|
|
@ -0,0 +1,135 @@
|
||||||
|
var Ellipse, EllipseView, Glyph, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
EllipseView = (function(superClass) {
|
||||||
|
extend(EllipseView, superClass);
|
||||||
|
|
||||||
|
function EllipseView() {
|
||||||
|
return EllipseView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
EllipseView.prototype._set_data = function() {
|
||||||
|
this.max_w2 = 0;
|
||||||
|
if (this.model.properties.width.units === "data") {
|
||||||
|
this.max_w2 = this.max_width / 2;
|
||||||
|
}
|
||||||
|
this.max_h2 = 0;
|
||||||
|
if (this.model.properties.height.units === "data") {
|
||||||
|
return this.max_h2 = this.max_height / 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EllipseView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
EllipseView.prototype._map_data = function() {
|
||||||
|
if (this.model.properties.width.units === "data") {
|
||||||
|
this.sw = this.sdist(this.renderer.xmapper, this._x, this._width, 'center');
|
||||||
|
} else {
|
||||||
|
this.sw = this._width;
|
||||||
|
}
|
||||||
|
if (this.model.properties.height.units === "data") {
|
||||||
|
return this.sh = this.sdist(this.renderer.ymapper, this._y, this._height, 'center');
|
||||||
|
} else {
|
||||||
|
return this.sh = this._height;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EllipseView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var i, j, len, results, sh, sw, sx, sy;
|
||||||
|
sx = arg.sx, sy = arg.sy, sw = arg.sw, sh = arg.sh;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sx[i] + sy[i] + sw[i] + sh[i] + this._angle[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.ellipse(sx[i], sy[i], sw[i] / 2.0, sh[i] / 2.0, this._angle[i], 0, 2 * Math.PI);
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
EllipseView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
var d, data, indices, ref, reference_point, scale, sh, sw, sx, sy;
|
||||||
|
reference_point = (ref = this.get_reference_point()) != null ? ref : 0;
|
||||||
|
indices = [reference_point];
|
||||||
|
sx = {};
|
||||||
|
sx[reference_point] = (x0 + x1) / 2;
|
||||||
|
sy = {};
|
||||||
|
sy[reference_point] = (y0 + y1) / 2;
|
||||||
|
scale = this.sw[reference_point] / this.sh[reference_point];
|
||||||
|
d = Math.min(Math.abs(x1 - x0), Math.abs(y1 - y0)) * 0.8;
|
||||||
|
sw = {};
|
||||||
|
sh = {};
|
||||||
|
if (scale > 1) {
|
||||||
|
sw[reference_point] = d;
|
||||||
|
sh[reference_point] = d / scale;
|
||||||
|
} else {
|
||||||
|
sw[reference_point] = d * scale;
|
||||||
|
sh[reference_point] = d;
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
sx: sx,
|
||||||
|
sy: sy,
|
||||||
|
sw: sw,
|
||||||
|
sh: sh
|
||||||
|
};
|
||||||
|
return this._render(ctx, indices, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
EllipseView.prototype._bounds = function(bds) {
|
||||||
|
return this.max_wh2_bounds(bds);
|
||||||
|
};
|
||||||
|
|
||||||
|
return EllipseView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Ellipse = (function(superClass) {
|
||||||
|
extend(Ellipse, superClass);
|
||||||
|
|
||||||
|
function Ellipse() {
|
||||||
|
return Ellipse.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ellipse.prototype.default_view = EllipseView;
|
||||||
|
|
||||||
|
Ellipse.prototype.type = 'Ellipse';
|
||||||
|
|
||||||
|
Ellipse.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Ellipse.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
Ellipse.define({
|
||||||
|
angle: [p.AngleSpec, 0.0],
|
||||||
|
width: [p.DistanceSpec],
|
||||||
|
height: [p.DistanceSpec]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ellipse;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Ellipse,
|
||||||
|
View: EllipseView
|
||||||
|
};
|
|
@ -0,0 +1,167 @@
|
||||||
|
var Bezier, Gear, GearUtils, GearView, Glyph, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
GearUtils = require("gear_utils");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Bezier = require("../../util/bezier");
|
||||||
|
|
||||||
|
GearView = (function(superClass) {
|
||||||
|
extend(GearView, superClass);
|
||||||
|
|
||||||
|
function GearView() {
|
||||||
|
return GearView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
GearView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
GearView.prototype._map_data = function() {
|
||||||
|
return this.smodule = this.sdist(this.renderer.xmapper, this._x, this._module, 'edge');
|
||||||
|
};
|
||||||
|
|
||||||
|
GearView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var M, _angle, _internal, _pressure_angle, _shaft_size, _teeth, fn, i, j, k, l, len, pitch_radius, ref, ref1, rim_radius, rot, seq, seq0, shaft_radius, smodule, sx, sy, x, y;
|
||||||
|
sx = arg.sx, sy = arg.sy, smodule = arg.smodule, _angle = arg._angle, _teeth = arg._teeth, _pressure_angle = arg._pressure_angle, _shaft_size = arg._shaft_size, _internal = arg._internal;
|
||||||
|
for (k = 0, len = indices.length; k < len; k++) {
|
||||||
|
i = indices[k];
|
||||||
|
if (isNaN(sx[i] + sy[i] + _angle[i] + smodule[i] + _teeth[i] + _pressure_angle[i] + _shaft_size[i] + _internal[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pitch_radius = smodule[i] * _teeth[i] / 2;
|
||||||
|
if (_internal[i]) {
|
||||||
|
fn = GearUtils.create_internal_gear_tooth;
|
||||||
|
} else {
|
||||||
|
fn = GearUtils.create_gear_tooth;
|
||||||
|
}
|
||||||
|
seq0 = fn(smodule[i], _teeth[i], _pressure_angle[i]);
|
||||||
|
ref = seq0.slice(0, 3), M = ref[0], x = ref[1], y = ref[2];
|
||||||
|
seq = seq0.slice(3);
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(sx[i], sy[i]);
|
||||||
|
ctx.rotate(_angle[i]);
|
||||||
|
ctx.beginPath();
|
||||||
|
rot = 2 * Math.PI / _teeth[i];
|
||||||
|
ctx.moveTo(x, y);
|
||||||
|
for (j = l = 0, ref1 = _teeth[i]; 0 <= ref1 ? l < ref1 : l > ref1; j = 0 <= ref1 ? ++l : --l) {
|
||||||
|
this._render_seq(ctx, seq);
|
||||||
|
ctx.rotate(rot);
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
|
if (_internal[i]) {
|
||||||
|
rim_radius = pitch_radius + 2.75 * smodule[i];
|
||||||
|
ctx.moveTo(rim_radius, 0);
|
||||||
|
ctx.arc(0, 0, rim_radius, 0, 2 * Math.PI, true);
|
||||||
|
} else if (_shaft_size[i] > 0) {
|
||||||
|
shaft_radius = pitch_radius * _shaft_size[i];
|
||||||
|
ctx.moveTo(shaft_radius, 0);
|
||||||
|
ctx.arc(0, 0, shaft_radius, 0, 2 * Math.PI, true);
|
||||||
|
}
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GearView.prototype._render_seq = function(ctx, seq) {
|
||||||
|
var c, cx0, cx1, cy0, cy1, i, k, large_arc, len, px, py, ref, ref1, ref10, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rx, ry, segments, sweep, x, x_rotation, y;
|
||||||
|
i = 0;
|
||||||
|
while (i < seq.length) {
|
||||||
|
if (_.isString(seq[i])) {
|
||||||
|
c = seq[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case "M":
|
||||||
|
ref = seq.slice(i, i + 2), x = ref[0], y = ref[1];
|
||||||
|
ctx.moveTo(x, y);
|
||||||
|
ref1 = [x, y], px = ref1[0], py = ref1[1];
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case "L":
|
||||||
|
ref2 = seq.slice(i, i + 2), x = ref2[0], y = ref2[1];
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
ref3 = [x, y], px = ref3[0], py = ref3[1];
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
case "C":
|
||||||
|
ref4 = seq.slice(i, i + 6), cx0 = ref4[0], cy0 = ref4[1], cx1 = ref4[2], cy1 = ref4[3], x = ref4[4], y = ref4[5];
|
||||||
|
ctx.bezierCurveTo(cx0, cy0, cx1, cy1, x, y);
|
||||||
|
ref5 = [x, y], px = ref5[0], py = ref5[1];
|
||||||
|
i += 6;
|
||||||
|
break;
|
||||||
|
case "Q":
|
||||||
|
ref6 = seq.slice(i, i + 4), cx0 = ref6[0], cy0 = ref6[1], x = ref6[2], y = ref6[3];
|
||||||
|
ctx.quadraticCurveTo(cx0, cy0, x, y);
|
||||||
|
ref7 = [x, y], px = ref7[0], py = ref7[1];
|
||||||
|
i += 4;
|
||||||
|
break;
|
||||||
|
case "A":
|
||||||
|
ref8 = seq.slice(i, i + 7), rx = ref8[0], ry = ref8[1], x_rotation = ref8[2], large_arc = ref8[3], sweep = ref8[4], x = ref8[5], y = ref8[6];
|
||||||
|
segments = Bezier.arc_to_bezier(px, py, rx, ry, -x_rotation, large_arc, 1 - sweep, x, y);
|
||||||
|
for (k = 0, len = segments.length; k < len; k++) {
|
||||||
|
ref9 = segments[k], cx0 = ref9[0], cy0 = ref9[1], cx1 = ref9[2], cy1 = ref9[3], x = ref9[4], y = ref9[5];
|
||||||
|
ctx.bezierCurveTo(cx0, cy0, cx1, cy1, x, y);
|
||||||
|
}
|
||||||
|
ref10 = [x, y], px = ref10[0], py = ref10[1];
|
||||||
|
i += 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("unexpected command: " + c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GearView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
return this._generic_area_legend(ctx, x0, x1, y0, y1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return GearView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Gear = (function(superClass) {
|
||||||
|
extend(Gear, superClass);
|
||||||
|
|
||||||
|
function Gear() {
|
||||||
|
return Gear.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gear.prototype.default_view = GearView;
|
||||||
|
|
||||||
|
Gear.prototype.type = 'Gear';
|
||||||
|
|
||||||
|
Gear.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Gear.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
Gear.define({
|
||||||
|
angle: [p.AngleSpec, 0],
|
||||||
|
module: [p.NumberSpec, null],
|
||||||
|
pressure_angle: [p.NumberSpec, 20],
|
||||||
|
shaft_size: [p.NumberSpec, 0.3],
|
||||||
|
teeth: [p.NumberSpec, null],
|
||||||
|
internal: [p.NumberSpec, false]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Gear;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Gear,
|
||||||
|
View: GearView
|
||||||
|
};
|
|
@ -0,0 +1,304 @@
|
||||||
|
var CategoricalMapper, Glyph, GlyphView, Model, Renderer, _, bbox, bokehgl, p, rbush,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
rbush = require("rbush");
|
||||||
|
|
||||||
|
CategoricalMapper = require("../mappers/categorical_mapper");
|
||||||
|
|
||||||
|
Renderer = require("../renderers/renderer");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
bbox = require("../../core/util/bbox");
|
||||||
|
|
||||||
|
Model = require("../../model");
|
||||||
|
|
||||||
|
bokehgl = require("./webgl/main");
|
||||||
|
|
||||||
|
GlyphView = (function(superClass) {
|
||||||
|
extend(GlyphView, superClass);
|
||||||
|
|
||||||
|
function GlyphView() {
|
||||||
|
return GlyphView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphView.prototype.initialize = function(options) {
|
||||||
|
var Cls, ctx, ref;
|
||||||
|
GlyphView.__super__.initialize.call(this, options);
|
||||||
|
this.renderer = options.renderer;
|
||||||
|
if (((ref = this.renderer) != null ? ref.plot_view : void 0) != null) {
|
||||||
|
ctx = this.renderer.plot_view.canvas_view.ctx;
|
||||||
|
if (ctx.glcanvas != null) {
|
||||||
|
Cls = bokehgl[this.model.type + 'GLGlyph'];
|
||||||
|
if (Cls) {
|
||||||
|
return this.glglyph = new Cls(ctx.glcanvas.gl, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.render = function(ctx, indices, data) {
|
||||||
|
if (this.mget("visible")) {
|
||||||
|
ctx.beginPath();
|
||||||
|
if (this.glglyph != null) {
|
||||||
|
if (this._render_gl(ctx, indices, data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._render(ctx, indices, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype._render_gl = function(ctx, indices, mainglyph) {
|
||||||
|
var dx, dy, ref, ref1, ref2, sx, sy, trans, wx, wy;
|
||||||
|
wx = wy = 1;
|
||||||
|
ref = this.renderer.map_to_screen([0 * wx, 1 * wx, 2 * wx], [0 * wy, 1 * wy, 2 * wy]), dx = ref[0], dy = ref[1];
|
||||||
|
wx = 100 / Math.min(Math.max(Math.abs(dx[1] - dx[0]), 1e-12), 1e12);
|
||||||
|
wy = 100 / Math.min(Math.max(Math.abs(dy[1] - dy[0]), 1e-12), 1e12);
|
||||||
|
ref1 = this.renderer.map_to_screen([0 * wx, 1 * wx, 2 * wx], [0 * wy, 1 * wy, 2 * wy]), dx = ref1[0], dy = ref1[1];
|
||||||
|
if (Math.abs((dx[1] - dx[0]) - (dx[2] - dx[1])) > 1e-6 || Math.abs((dy[1] - dy[0]) - (dy[2] - dy[1])) > 1e-6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ref2 = [(dx[1] - dx[0]) / wx, (dy[1] - dy[0]) / wy], sx = ref2[0], sy = ref2[1];
|
||||||
|
trans = {
|
||||||
|
pixel_ratio: ctx.pixel_ratio,
|
||||||
|
width: ctx.glcanvas.width,
|
||||||
|
height: ctx.glcanvas.height,
|
||||||
|
dx: dx[0] / sx,
|
||||||
|
dy: dy[0] / sy,
|
||||||
|
sx: sx,
|
||||||
|
sy: sy
|
||||||
|
};
|
||||||
|
this.glglyph.draw(indices, mainglyph, trans);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.bounds = function() {
|
||||||
|
var bb, d;
|
||||||
|
if (this.index == null) {
|
||||||
|
return bbox.empty();
|
||||||
|
}
|
||||||
|
d = this.index.data;
|
||||||
|
bb = {
|
||||||
|
minX: d.minX,
|
||||||
|
minY: d.minY,
|
||||||
|
maxX: d.maxX,
|
||||||
|
maxY: d.maxY
|
||||||
|
};
|
||||||
|
return this._bounds(bb);
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.max_wh2_bounds = function(bds) {
|
||||||
|
return {
|
||||||
|
minX: bds.minX - this.max_w2,
|
||||||
|
maxX: bds.maxX + this.max_w2,
|
||||||
|
minY: bds.minY - this.max_h2,
|
||||||
|
maxY: bds.maxY + this.max_h2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.get_anchor_point = function(anchor, i, arg) {
|
||||||
|
var sx, sy;
|
||||||
|
sx = arg[0], sy = arg[1];
|
||||||
|
switch (anchor) {
|
||||||
|
case "center":
|
||||||
|
return {
|
||||||
|
x: this.scx(i, sx, sy),
|
||||||
|
y: this.scy(i, sx, sy)
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.scx = function(i) {
|
||||||
|
return this.sx[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.scy = function(i) {
|
||||||
|
return this.sy[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype._xy_index = function() {
|
||||||
|
var i, index, j, pts, ref, x, xx, y, yy;
|
||||||
|
index = rbush();
|
||||||
|
pts = [];
|
||||||
|
if (this.renderer.xmapper instanceof CategoricalMapper.Model) {
|
||||||
|
xx = this.renderer.xmapper.v_map_to_target(this._x, true);
|
||||||
|
} else {
|
||||||
|
xx = this._x;
|
||||||
|
}
|
||||||
|
if (this.renderer.ymapper instanceof CategoricalMapper.Model) {
|
||||||
|
yy = this.renderer.ymapper.v_map_to_target(this._y, true);
|
||||||
|
} else {
|
||||||
|
yy = this._y;
|
||||||
|
}
|
||||||
|
for (i = j = 0, ref = xx.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
x = xx[i];
|
||||||
|
if (isNaN(x) || !isFinite(x)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
y = yy[i];
|
||||||
|
if (isNaN(y) || !isFinite(y)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pts.push({
|
||||||
|
minX: x,
|
||||||
|
minY: y,
|
||||||
|
maxX: x,
|
||||||
|
maxY: y,
|
||||||
|
i: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
index.load(pts);
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.sdist = function(mapper, pts, spans, pts_location, dilate) {
|
||||||
|
var d, halfspan, i, pt0, pt1, spt0, spt1;
|
||||||
|
if (pts_location == null) {
|
||||||
|
pts_location = "edge";
|
||||||
|
}
|
||||||
|
if (dilate == null) {
|
||||||
|
dilate = false;
|
||||||
|
}
|
||||||
|
if (_.isString(pts[0])) {
|
||||||
|
pts = mapper.v_map_to_target(pts);
|
||||||
|
}
|
||||||
|
if (pts_location === 'center') {
|
||||||
|
halfspan = (function() {
|
||||||
|
var j, len, results;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = spans.length; j < len; j++) {
|
||||||
|
d = spans[j];
|
||||||
|
results.push(d / 2);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
pt0 = (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = pts.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(pts[i] - halfspan[i]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
pt1 = (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = pts.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(pts[i] + halfspan[i]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
pt0 = pts;
|
||||||
|
pt1 = (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = pt0.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(pt0[i] + spans[i]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
spt0 = mapper.v_map_to_target(pt0);
|
||||||
|
spt1 = mapper.v_map_to_target(pt1);
|
||||||
|
if (dilate) {
|
||||||
|
return (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = spt0.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(Math.ceil(Math.abs(spt1[i] - spt0[i])));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
return (function() {
|
||||||
|
var j, ref, results;
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = spt0.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
results.push(Math.abs(spt1[i] - spt0[i]));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.get_reference_point = function() {
|
||||||
|
return void 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype.draw_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype._generic_line_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
var ref, reference_point;
|
||||||
|
reference_point = (ref = this.get_reference_point()) != null ? ref : 0;
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x0, (y0 + y1) / 2);
|
||||||
|
ctx.lineTo(x1, (y0 + y1) / 2);
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
this.visuals.line.set_vectorize(ctx, reference_point);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
return ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
GlyphView.prototype._generic_area_legend = function(ctx, x0, x1, y0, y1) {
|
||||||
|
var dh, dw, h, indices, ref, reference_point, sx0, sx1, sy0, sy1, w;
|
||||||
|
reference_point = (ref = this.get_reference_point()) != null ? ref : 0;
|
||||||
|
indices = [reference_point];
|
||||||
|
w = Math.abs(x1 - x0);
|
||||||
|
dw = w * 0.1;
|
||||||
|
h = Math.abs(y1 - y0);
|
||||||
|
dh = h * 0.1;
|
||||||
|
sx0 = x0 + dw;
|
||||||
|
sx1 = x1 - dw;
|
||||||
|
sy0 = y0 + dh;
|
||||||
|
sy1 = y1 - dh;
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, reference_point);
|
||||||
|
ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(sx0, sy0, sx1 - sx0, sy1 - sy0);
|
||||||
|
this.visuals.line.set_vectorize(ctx, reference_point);
|
||||||
|
return ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return GlyphView;
|
||||||
|
|
||||||
|
})(Renderer.View);
|
||||||
|
|
||||||
|
Glyph = (function(superClass) {
|
||||||
|
extend(Glyph, superClass);
|
||||||
|
|
||||||
|
function Glyph() {
|
||||||
|
return Glyph.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Glyph.define({
|
||||||
|
visible: [p.Bool, true]
|
||||||
|
});
|
||||||
|
|
||||||
|
Glyph.internal({
|
||||||
|
x_range_name: [p.String, 'default'],
|
||||||
|
y_range_name: [p.String, 'default']
|
||||||
|
});
|
||||||
|
|
||||||
|
return Glyph;
|
||||||
|
|
||||||
|
})(Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Glyph,
|
||||||
|
View: GlyphView
|
||||||
|
};
|
|
@ -0,0 +1,164 @@
|
||||||
|
var CategoricalMapper, Glyph, HBar, HBarView, Quad, _, hittest, p, rbush,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
rbush = require("rbush");
|
||||||
|
|
||||||
|
Quad = require("./quad");
|
||||||
|
|
||||||
|
Glyph = require("./glyph");
|
||||||
|
|
||||||
|
CategoricalMapper = require("../mappers/categorical_mapper");
|
||||||
|
|
||||||
|
hittest = require("../../common/hittest");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
HBarView = (function(superClass) {
|
||||||
|
extend(HBarView, superClass);
|
||||||
|
|
||||||
|
function HBarView() {
|
||||||
|
return HBarView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
HBarView.prototype._map_data = function() {
|
||||||
|
var i, j, ref, vleft, vright, vy;
|
||||||
|
vy = this.renderer.ymapper.v_map_to_target(this._y);
|
||||||
|
this.sy = this.plot_view.canvas.v_vy_to_sy(vy);
|
||||||
|
vright = this.renderer.xmapper.v_map_to_target(this._right);
|
||||||
|
vleft = this.renderer.xmapper.v_map_to_target(this._left);
|
||||||
|
this.sright = this.plot_view.canvas.v_vx_to_sx(vright);
|
||||||
|
this.sleft = this.plot_view.canvas.v_vx_to_sx(vleft);
|
||||||
|
this.stop = [];
|
||||||
|
this.sbottom = [];
|
||||||
|
this.sh = this.sdist(this.renderer.ymapper, this._y, this._height, 'center');
|
||||||
|
for (i = j = 0, ref = this.sy.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
this.stop.push(this.sy[i] - this.sh[i] / 2);
|
||||||
|
this.sbottom.push(this.sy[i] + this.sh[i] / 2);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
HBarView.prototype._index_data = function() {
|
||||||
|
var b, height, i, index, j, l, left, map_to_synthetic, pts, r, ref, right, t, y;
|
||||||
|
map_to_synthetic = function(mapper, array) {
|
||||||
|
if (mapper instanceof CategoricalMapper.Model) {
|
||||||
|
return mapper.v_map_to_target(array, true);
|
||||||
|
} else {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
left = map_to_synthetic(this.renderer.xmapper, this._left);
|
||||||
|
right = map_to_synthetic(this.renderer.xmapper, this._right);
|
||||||
|
y = map_to_synthetic(this.renderer.ymapper, this._y);
|
||||||
|
height = map_to_synthetic(this.renderer.ymapper, this._height);
|
||||||
|
index = rbush();
|
||||||
|
pts = [];
|
||||||
|
for (i = j = 0, ref = y.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
l = left[i];
|
||||||
|
r = right[i];
|
||||||
|
t = y[i] + 0.5 * height[i];
|
||||||
|
b = y[i] - 0.5 * height[i];
|
||||||
|
if (isNaN(l + r + t + b) || !isFinite(l + r + t + b)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pts.push({
|
||||||
|
minX: l,
|
||||||
|
minY: b,
|
||||||
|
maxX: r,
|
||||||
|
maxY: t,
|
||||||
|
i: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
index.load(pts);
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
|
||||||
|
HBarView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var i, j, len, results, sbottom, sleft, sright, stop;
|
||||||
|
sleft = arg.sleft, sright = arg.sright, stop = arg.stop, sbottom = arg.sbottom;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (isNaN(sleft[i] + stop[i] + sright[i] + sbottom[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.visuals.fill.doit) {
|
||||||
|
this.visuals.fill.set_vectorize(ctx, i);
|
||||||
|
ctx.fillRect(sleft[i], stop[i], sright[i] - sleft[i], sbottom[i] - stop[i]);
|
||||||
|
}
|
||||||
|
if (this.visuals.line.doit) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(sleft[i], stop[i], sright[i] - sleft[i], sbottom[i] - stop[i]);
|
||||||
|
this.visuals.line.set_vectorize(ctx, i);
|
||||||
|
results.push(ctx.stroke());
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
HBarView.prototype._hit_point = function(geometry) {
|
||||||
|
var hits, ref, result, vx, vy, x, y;
|
||||||
|
ref = [geometry.vx, geometry.vy], vx = ref[0], vy = ref[1];
|
||||||
|
x = this.renderer.xmapper.map_from_target(vx, true);
|
||||||
|
y = this.renderer.ymapper.map_from_target(vy, true);
|
||||||
|
hits = (function() {
|
||||||
|
var j, len, ref1, results;
|
||||||
|
ref1 = this.index.search({
|
||||||
|
minX: x,
|
||||||
|
minY: y,
|
||||||
|
maxX: x,
|
||||||
|
maxY: y
|
||||||
|
});
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref1.length; j < len; j++) {
|
||||||
|
x = ref1[j];
|
||||||
|
results.push(x.i);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}).call(this);
|
||||||
|
result = hittest.create_hit_test_result();
|
||||||
|
result['1d'].indices = hits;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
HBarView.prototype.scx = function(i) {
|
||||||
|
return (this.sleft[i] + this.sright[i]) / 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
return HBarView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
HBar = (function(superClass) {
|
||||||
|
extend(HBar, superClass);
|
||||||
|
|
||||||
|
function HBar() {
|
||||||
|
return HBar.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
HBar.prototype.default_view = HBarView;
|
||||||
|
|
||||||
|
HBar.prototype.type = 'HBar';
|
||||||
|
|
||||||
|
HBar.mixins(['line', 'fill']);
|
||||||
|
|
||||||
|
HBar.define({
|
||||||
|
y: [p.NumberSpec],
|
||||||
|
height: [p.DistanceSpec],
|
||||||
|
left: [p.NumberSpec, 0],
|
||||||
|
right: [p.NumberSpec]
|
||||||
|
});
|
||||||
|
|
||||||
|
return HBar;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: HBar,
|
||||||
|
View: HBarView
|
||||||
|
};
|
|
@ -0,0 +1,179 @@
|
||||||
|
var Glyph, Greys, Image, ImageView, LinearColorMapper, _, p,
|
||||||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
_ = require("underscore");
|
||||||
|
|
||||||
|
Glyph = require("../glyphs/glyph");
|
||||||
|
|
||||||
|
LinearColorMapper = require("../mappers/linear_color_mapper");
|
||||||
|
|
||||||
|
p = require("../../core/properties");
|
||||||
|
|
||||||
|
Greys = require('../../palettes/palettes').Greys;
|
||||||
|
|
||||||
|
ImageView = (function(superClass) {
|
||||||
|
extend(ImageView, superClass);
|
||||||
|
|
||||||
|
function ImageView() {
|
||||||
|
return ImageView.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageView.prototype.initialize = function(options) {
|
||||||
|
ImageView.__super__.initialize.call(this, options);
|
||||||
|
return this.listenTo(this.model.color_mapper, 'change', this._update_image);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype._update_image = function() {
|
||||||
|
if (this.image_data != null) {
|
||||||
|
this._set_data();
|
||||||
|
return this.plot_view.request_render();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype._index_data = function() {
|
||||||
|
return this._xy_index();
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype._set_data = function() {
|
||||||
|
var buf, buf8, canvas, cmap, ctx, i, image_data, img, j, ref, results;
|
||||||
|
if ((this.image_data == null) || this.image_data.length !== this._image.length) {
|
||||||
|
this.image_data = new Array(this._image.length);
|
||||||
|
}
|
||||||
|
if ((this._width == null) || this._width.length !== this._image.length) {
|
||||||
|
this._width = new Array(this._image.length);
|
||||||
|
}
|
||||||
|
if ((this._height == null) || this._height.length !== this._image.length) {
|
||||||
|
this._height = new Array(this._image.length);
|
||||||
|
}
|
||||||
|
results = [];
|
||||||
|
for (i = j = 0, ref = this._image.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||||||
|
if (this._rows != null) {
|
||||||
|
this._height[i] = this._rows[i];
|
||||||
|
this._width[i] = this._cols[i];
|
||||||
|
} else {
|
||||||
|
this._height[i] = this._image[i].length;
|
||||||
|
this._width[i] = this._image[i][0].length;
|
||||||
|
}
|
||||||
|
canvas = document.createElement('canvas');
|
||||||
|
canvas.width = this._width[i];
|
||||||
|
canvas.height = this._height[i];
|
||||||
|
ctx = canvas.getContext('2d');
|
||||||
|
image_data = ctx.getImageData(0, 0, this._width[i], this._height[i]);
|
||||||
|
cmap = this.mget('color_mapper');
|
||||||
|
if (this._rows != null) {
|
||||||
|
img = this._image[i];
|
||||||
|
} else {
|
||||||
|
img = _.flatten(this._image[i]);
|
||||||
|
}
|
||||||
|
buf = cmap.v_map_screen(img);
|
||||||
|
buf8 = new Uint8ClampedArray(buf);
|
||||||
|
image_data.data.set(buf8);
|
||||||
|
ctx.putImageData(image_data, 0, 0);
|
||||||
|
this.image_data[i] = canvas;
|
||||||
|
this.max_dw = 0;
|
||||||
|
if (this._dw.units === "data") {
|
||||||
|
this.max_dw = _.max(this._dw);
|
||||||
|
}
|
||||||
|
this.max_dh = 0;
|
||||||
|
if (this._dh.units === "data") {
|
||||||
|
this.max_dh = _.max(this._dh);
|
||||||
|
}
|
||||||
|
results.push(this._xy_index());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype._map_data = function() {
|
||||||
|
switch (this.model.properties.dw.units) {
|
||||||
|
case "data":
|
||||||
|
this.sw = this.sdist(this.renderer.xmapper, this._x, this._dw, 'edge', this.mget('dilate'));
|
||||||
|
break;
|
||||||
|
case "screen":
|
||||||
|
this.sw = this._dw;
|
||||||
|
}
|
||||||
|
switch (this.model.properties.dh.units) {
|
||||||
|
case "data":
|
||||||
|
return this.sh = this.sdist(this.renderer.ymapper, this._y, this._dh, 'edge', this.mget('dilate'));
|
||||||
|
case "screen":
|
||||||
|
return this.sh = this._dh;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype._render = function(ctx, indices, arg) {
|
||||||
|
var i, image_data, j, len, old_smoothing, sh, sw, sx, sy, y_offset;
|
||||||
|
image_data = arg.image_data, sx = arg.sx, sy = arg.sy, sw = arg.sw, sh = arg.sh;
|
||||||
|
old_smoothing = ctx.getImageSmoothingEnabled();
|
||||||
|
ctx.setImageSmoothingEnabled(false);
|
||||||
|
for (j = 0, len = indices.length; j < len; j++) {
|
||||||
|
i = indices[j];
|
||||||
|
if (image_data[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isNaN(sx[i] + sy[i] + sw[i] + sh[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
y_offset = sy[i];
|
||||||
|
ctx.translate(0, y_offset);
|
||||||
|
ctx.scale(1, -1);
|
||||||
|
ctx.translate(0, -y_offset);
|
||||||
|
ctx.drawImage(image_data[i], sx[i] | 0, sy[i] | 0, sw[i], sh[i]);
|
||||||
|
ctx.translate(0, y_offset);
|
||||||
|
ctx.scale(1, -1);
|
||||||
|
ctx.translate(0, -y_offset);
|
||||||
|
}
|
||||||
|
return ctx.setImageSmoothingEnabled(old_smoothing);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageView.prototype.bounds = function() {
|
||||||
|
var d;
|
||||||
|
d = this.index.data;
|
||||||
|
return {
|
||||||
|
minX: d.minX,
|
||||||
|
minY: d.minY,
|
||||||
|
maxX: d.maxX + this.max_dw,
|
||||||
|
maxY: d.maxY + this.max_dh
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ImageView;
|
||||||
|
|
||||||
|
})(Glyph.View);
|
||||||
|
|
||||||
|
Image = (function(superClass) {
|
||||||
|
extend(Image, superClass);
|
||||||
|
|
||||||
|
function Image() {
|
||||||
|
return Image.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image.prototype.default_view = ImageView;
|
||||||
|
|
||||||
|
Image.prototype.type = 'Image';
|
||||||
|
|
||||||
|
Image.coords([['x', 'y']]);
|
||||||
|
|
||||||
|
Image.mixins([]);
|
||||||
|
|
||||||
|
Image.define({
|
||||||
|
image: [p.NumberSpec],
|
||||||
|
dw: [p.DistanceSpec],
|
||||||
|
dh: [p.DistanceSpec],
|
||||||
|
dilate: [p.Bool, false],
|
||||||
|
color_mapper: [
|
||||||
|
p.Instance, function() {
|
||||||
|
return new LinearColorMapper.Model({
|
||||||
|
palette: Greys.Greys9
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return Image;
|
||||||
|
|
||||||
|
})(Glyph.Model);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Model: Image,
|
||||||
|
View: ImageView
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue