227 changes: 227 additions & 0 deletions docs/articles/DengueVignette_files/scatterD3-0.9.2/scatterD3-scales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@



// Compute x and y axes limits
function compute_limits(chart) {

var min_x, min_y, max_x, max_y, gap_x, gap_y;
var settings = chart.settings();
var data = chart.data();

// x and y limits
if (settings.xlim === null) {
min_x = d3v6.min(data, d => d.x);
max_x = d3v6.max(data, d => d.x);
gap_x = (max_x - min_x) * 0.2;
if (min_x == max_x) {
min_x = min_x * 0.8;
max_x = max_x * 1.2;
gap_x = 0;
}
if (min_x == 0 && max_x == 0) {
min_x = -1;
max_x = 1;
gap_x = 0.1;
}
} else {
min_x = settings.xlim[0];
max_x = settings.xlim[1];
gap_x = 0;
}
if (settings.ylim === null) {
min_y = d3v6.min(data, d => d.y);
max_y = d3v6.max(data, d => d.y);
gap_y = (max_y - min_y) * 0.2;
if (min_y == max_y) {
min_y = min_y * 0.8;
max_y = max_y * 1.2;
gap_y = 0;
}
if (min_y == 0 && max_y == 0) {
min_y = -1;
max_y = 1;
gap_y = 0.1;
}
} else {
min_y = settings.ylim[0];
max_y = settings.ylim[1];
gap_y = 0;
}

min_x = settings.x_log ? min_x * 0.8 : min_x - gap_x;
max_x = settings.x_log ? max_x * 1.3 : max_x + gap_x;
min_y = settings.y_log ? min_y * 0.9 : min_y - gap_y;
max_y = settings.y_log ? max_y * 1.1 : max_y + gap_y;

// Fixed ratio
var range_x = max_x - min_x;
var mid_x = (max_x + min_x) / 2;
var range_y = max_y - min_y;
var mid_y = (max_y + min_y) / 2;
if (settings.fixed && settings.xlim === null && settings.ylim === null) {
var ratio = (range_y / range_x);
if (ratio > 1) {
range_x = range_x * ratio;
min_x = mid_x - range_x / 2;
max_x = mid_x + range_x / 2;
} else {
range_y = range_y / ratio;
min_y = mid_y - range_y / 2;
max_y = mid_y + range_y / 2;
}
}
if (settings.fixed && settings.xlim != null) {
range_y = range_x;
min_y = mid_y - range_y / 2;
max_y = mid_y + range_y / 2;
}
if (settings.fixed && settings.ylim != null) {
range_x = range_y;
min_x = mid_x - range_x / 2;
max_x = mid_x + range_x / 2;
}

return {min_x: min_x, max_x: max_x, min_y: min_y, max_y: max_y};
}



// Compute and setup scales
function setup_scales(chart) {

var scales = {};
var settings = chart.settings();
var dims = chart.dims();
var data = chart.data();

// if data is empty
if (data.length == 0) {
settings.x_categorical = false;
settings.y_categorical = false;
chart.settings(settings);
chart.data([{ x: 0, y: 0, key: 1 }]);
}

var limits = compute_limits(chart);

// x, y scales
if (!settings.x_categorical) {
scales.x = settings.x_log ? d3v6.scaleLog() : d3v6.scaleLinear();
scales.x.range([0, dims.width])
.domain([limits.min_x, limits.max_x]);
} else {
var x_domain = settings.x_levels === null ?
[...new Set(data.map(d => d.x))].sort() :
settings.x_levels;
scales.x = d3v6.scalePoint()
.range([0, dims.width])
.padding(0.9)
.domain(x_domain);
}
if (!settings.y_categorical) {
scales.y = settings.y_log ? d3v6.scaleLog() : d3v6.scaleLinear();
scales.y.range([dims.height, 0])
.domain([limits.min_y, limits.max_y]);
} else {
var y_domain = settings.y_levels === null ?
[...new Set(data.map(d => d.y))].sort() :
settings.y_levels;
scales.y = d3v6.scalePoint()
.range([dims.height, 0])
.padding(0.9)
.domain(y_domain);
}
// Keep track of original scales
scales.x_orig = scales.x;
scales.y_orig = scales.y;
// x and y axis functions
scales.xAxis = d3v6.axisBottom(scales.x)
.tickSize(-dims.height);
if (!settings.x_categorical) {
scales.xAxis.tickFormat(d3v6.format(""));
}
scales.yAxis = d3v6.axisLeft(scales.y)
.tickSize(-dims.width);
if (!settings.y_categorical) {
scales.yAxis.tickFormat(d3v6.format(""));
}

// Continuous color scale
if (settings.col_continuous) {
if (settings.colors === null) {
scales.color = d3v6.scaleSequential(d3v6.interpolateViridis);
} else {
scales.color = d3v6.scaleSequential(d3v6[settings.colors]);
}
scales.color = scales.color
.domain([d3v6.min(data, d => d.col_var),
d3v6.max(data, d => d.col_var)]);
}
// Ordinal color scale
else {
if (settings.colors === null) {
// Number of different levels. See https://github.com/mbostock/d3/issues/472
var n = new Set(data.map(d => d.col_var)).size;
scales.color = n <= 10 ? d3v6.scaleOrdinal(custom_scheme10()) : d3v6.scaleOrdinal(d3v6.schemePaired);
} else if (Array.isArray(settings.colors)) {
scales.color = d3v6.scaleOrdinal().range(settings.colors);
} else if (typeof (settings.colors) === "string") {
// Single string given
scales.color = d3v6.scaleOrdinal().range(Array(settings.colors));
} else if (typeof (settings.colors) === "object") {
scales.color = d3v6.scaleOrdinal()
.range(Object.values(settings.colors))
.domain(Object.keys(settings.colors));
}
}

// Symbol scale
var symbol_table = {
"circle": d3v6.symbolCircle,
"cross": d3v6.symbolCross,
"diamond": d3v6.symbolDiamond,
"square": d3v6.symbolSquare,
"star": d3v6.symbolStar,
"triangle": d3v6.symbolTriangle,
"wye": d3v6.symbolWye,
}
if (settings.symbols === null) {
scales.symbol = d3v6.scaleOrdinal().range(d3v6.symbols);
} else if (Array.isArray(settings.symbols)) {
scales.symbol = d3v6.scaleOrdinal().range(settings.symbols.map(d => symbol_table[d]));
} else if (typeof (settings.symbols) === "string") {
// Single string given
scales.symbol = d3v6.scaleOrdinal().range(Array(symbol_table[settings.symbols]));
} else if (typeof (settings.symbols) === "object") {
scales.symbol = d3v6.scaleOrdinal()
.range(Object.values(settings.symbols).map(d => symbol_table[d]))
.domain(Object.keys(settings.symbols))
}

// Size scale
if (settings.sizes === null) {
scales.size = d3v6.scaleLinear()
.range(settings.size_range)
.domain([d3v6.min(data, d => d.size_var),
d3v6.max(data, d => d.size_var)]);
} else if (typeof(settings.sizes) === "object") {
scales.size = d3v6.scaleOrdinal()
.range(Object.values(settings.sizes))
.domain(Object.keys(settings.sizes));
}

// Opacity scale
if (settings.opacities === null) {
scales.opacity = d3v6.scaleLinear()
.range([0.1, 1])
.domain([d3v6.min(data, d => d.opacity_var),
d3v6.max(data, d => d.opacity_var)]);
} else if (typeof(settings.opacities) === "object") {
scales.opacity = d3v6.scaleOrdinal()
.range(Object.values(settings.opacities))
.domain(Object.keys(settings.opacities));
}

return scales;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Clean variables levels to be valid CSS classes
function css_clean(s) {
if (s === undefined) return "";
return s.toString().replace(/[^\w-]/g, "_");
}

// Default translation function for points and labels
function translation(d, scales) {
return "translate(" + scales.x(d.x) + "," + scales.y(d.y) + ")";
}

// Key function to identify rows when interactively filtering
function key(d) {
return d.key_var;
}


// Create tooltip content function
function tooltip_content(d, chart) {

var settings = chart.settings();

// no tooltips
if (!settings.has_tooltips) return null;
if (settings.has_custom_tooltips) {
// custom tooltipsl
return d.tooltip_text;
} else {
// default tooltips
var text = Array();
if (settings.has_labels) text.push("<b>" + d.lab + "</b>");
var x_value = settings.x_categorical ? d.x : d.x.toFixed(3);
var y_value = settings.y_categorical ? d.y : d.y.toFixed(3);
text.push("<b>" + settings.xlab + ":</b> " + x_value);
text.push("<b>" + settings.ylab + ":</b> " + y_value);
if (settings.has_color_var) text.push("<b>" + settings.col_lab + ":</b> " + d.col_var);
if (settings.has_symbol_var) text.push("<b>" + settings.symbol_lab + ":</b> " + d.symbol_var);
if (settings.has_size_var) text.push("<b>" + settings.size_lab + ":</b> " + d.size_var);
if (settings.has_opacity_var) text.push("<b>" + settings.opacity_lab + ":</b> " + d.opacity_var);
return text.join("<br />");
}
}

// Custom color scheme
function custom_scheme10() {
// slice() to create a copy
var scheme = d3v6.schemeCategory10.slice();
// Switch orange and red
var tmp = scheme[3];
scheme[3] = scheme[1];
scheme[1] = tmp;
return scheme;
}

// Gear icon path
function gear_path() {
return "m 24.28,7.2087374 -1.307796,0 c -0.17052,-0.655338 -0.433486,-1.286349 -0.772208,-1.858846 l 0.927566,-0.929797 c 0.281273,-0.281188 0.281273,-0.738139 0,-1.019312 L 21.600185,1.8728727 C 21.319088,1.591685 20.863146,1.5914219 20.582048,1.8726096 L 19.650069,2.8001358 C 19.077606,2.4614173 18.446602,2.1982296 17.791262,2.0278389 l 0,-1.30783846 c 0,-0.39762 -0.313645,-0.72 -0.711262,-0.72 l -2.16,0 c -0.397618,0 -0.711262,0.32238 -0.711262,0.72 l 0,1.30783846 c -0.65534,0.1703907 -1.286345,0.43344 -1.858849,0.7722138 L 11.420092,1.8724435 c -0.281185,-0.2812846 -0.738131,-0.2812846 -1.019315,0 L 8.8728737,3.3998124 C 8.5916888,3.6809174 8.591427,4.1368574 8.872612,4.4179484 l 0.9275234,0.931984 c -0.3388099,0.572456 -0.6019076,1.203467 -0.7722956,1.858805 l -1.3078398,0 c -0.3976159,0 -0.72,0.313643 -0.72,0.711263 L 7,10.08 c 0,0.397661 0.3223841,0.711263 0.72,0.711263 l 1.3078398,0 c 0.170388,0.655338 0.4334414,1.286349 0.7722084,1.858846 L 8.872349,13.579906 c -0.2811836,0.281105 -0.2811836,0.738139 0,1.019188 l 1.527378,1.527951 c 0.281185,0.28127 0.737041,0.281533 1.018224,3.04e-4 l 0.931981,-0.927484 c 0.572461,0.338718 1.203466,0.601823 1.858806,0.772338 l 0,1.307797 c 0,0.397662 0.313644,0.72 0.711262,0.72 l 2.16,0 c 0.39766,0 0.711262,-0.32238 0.711262,-0.72 l 0,-1.307797 c 0.65534,-0.170515 1.286344,-0.433481 1.858849,-0.772214 l 0.929797,0.927568 c 0.281098,0.281271 0.738131,0.281271 1.019184,0 l 1.527947,-1.527369 c 0.281273,-0.281105 0.281534,-0.737045 3.06e-4,-1.018136 l -0.92748,-0.931984 c 0.338723,-0.572456 0.601819,-1.203467 0.772339,-1.858805 l 1.307796,0 c 0.39766,0 0.72,-0.313643 0.72,-0.711263 l 0,-2.1599996 c 0,-0.39762 -0.322384,-0.711263 -0.72,-0.711263 z M 16,12.6 c -1.988258,0 -3.6,-1.611789 -3.6,-3.5999996 0,-1.988252 1.611742,-3.6 3.6,-3.6 1.988258,0 3.6,1.611748 3.6,3.6 C 19.6,10.988252 17.988258,12.6 16,12.6 Z";
}

// Caption icon path
function caption_path() {
return "m 9.0084765,0.0032163 q 1.8249645,0 3.4939395,0.7097539 1.668974,0.7096153 2.87781,1.918523 1.208839,1.2087707 1.91855,2.8777847 0.709702,1.6690155 0.709702,3.4939387 0,1.8249234 -0.709702,3.4939384 -0.709711,1.669015 -1.91855,2.877784 -1.208836,1.208907 -2.87781,1.918523 -1.668975,0.709754 -3.4939395,0.709754 -1.8249502,0 -3.493924,-0.709754 Q 3.8455651,16.583846 2.6367267,15.374939 1.4278885,14.16617 0.71819,12.497155 0.0084778,10.82814 0.0084778,9.0032166 0.0084778,7.1782934 0.71819,5.5092779 1.4278885,3.8402625 2.6367267,2.6314932 3.8455651,1.4225855 5.5145525,0.7129702 7.1835263,0.0032163 9.0084765,0.0032163 Z m 1.1698475,2.760786 -2.339681,0 q -0.1559905,0 -0.2729632,0.1176924 -0.117,0.1163076 -0.117,0.2730462 l 0,2.3395847 q 0,0.1560462 0.117,0.2730447 0.117,0.1176924 0.2729632,0.1176924 l 2.339681,0 q 0.155977,0 0.272963,-0.1176924 0.117,-0.1163076 0.117,-0.2730447 l 0,-2.3395847 q 0,-0.1560462 -0.117,-0.2730462 -0.117,-0.1176924 -0.272963,-0.1176924 z m 0,4.6794463 -3.8994777,0 q -0.1559772,0 -0.272963,0.1176924 -0.117,0.1163076 -0.117,0.2729078 l 0,0.7799524 q 0,0.1559078 0.117,0.2729078 0.117,0.1163076 0.272963,0.1163076 l 1.1698475,0 0,3.1195394 -1.1698475,0 q -0.1559772,0 -0.272963,0.117696 -0.117,0.116304 -0.117,0.273046 l 0,0.779815 q 0,0.156046 0.117,0.273046 0.117,0.116304 0.272963,0.116304 l 5.4592747,0 q 0.155977,0 0.272964,-0.116304 0.117,-0.116304 0.117,-0.273046 l 0,-0.779815 q 0,-0.156046 -0.117,-0.273046 -0.117,-0.117696 -0.272964,-0.117696 l -1.169848,0 0,-4.2893996 q 0,-0.1559078 -0.117,-0.2729078 -0.117,-0.1176924 -0.272963,-0.1176924 z";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

// Init and returns a zoom behavior
function zoom_behavior(chart) {

var root = chart.svg().select(".root");
var viewport = chart.svg().select(".viewport");

var root_bb = root.node().getBoundingClientRect();
var viewport_bb = viewport.node().getBoundingClientRect();

var x0 = viewport_bb.left - root_bb.left;
var y0 = viewport_bb.top - root_bb.top;
var x1 = viewport_bb.right - root_bb.left;
var y1 = viewport_bb.bottom - root_bb.top;

// Zoom behavior
var zoom = d3v6.zoom()
.extent([[0, y0], [x1 - x0, y1]])
.scaleExtent([0, 32])
.on("zoom", (event) => zoomed(event, chart));

return zoom;
}

// Zoom function
function zoomed(event, chart) {

var root = chart.svg().select(".root");

if (!chart.settings().x_categorical) {
chart.scales().x = event.transform.rescaleX(chart.scales().x_orig);
chart.scales().xAxis = chart.scales().xAxis.scale(chart.scales().x);
root.select(".x.axis").call(chart.scales().xAxis);
}
if (!chart.settings().y_categorical) {
chart.scales().y = event.transform.rescaleY(chart.scales().y_orig);
chart.scales().yAxis = chart.scales().yAxis.scale(chart.scales().y);
root.select(".y.axis").call(chart.scales().yAxis);
}

var chart_body = chart.svg().select(".chart-body");

chart_body.selectAll(".dot, .point-label, .point-label-line")
.attr("transform", d => ( translation(d, chart.scales()) ));
chart_body.selectAll(".line").call(line_formatting, chart)
chart_body.selectAll(".arrow").call(draw_arrow, chart);
chart_body.selectAll(".ellipse").call(ellipse_formatting, chart);
chart.svg().select(".unit-circle").call(unit_circle_formatting, chart);

if (typeof chart.settings().zoom_callback === 'function') {
chart.settings().zoom_callback(chart.scales().x.domain()[0], chart.scales().x.domain()[1],
chart.scales().y.domain()[0], chart.scales().y.domain()[1]);
}

}

// Reset zoom function
function reset_zoom(chart) {
var root = chart.svg().select(".root");
root.transition().duration(1000)
.call(chart.zoom().transform, d3v6.zoomIdentity);
}

// Update zoom function
function update_zoom(chart) {
var root = chart.svg().select(".root");
root.select(".x.axis")
.transition().duration(1000)
.call(chart.scales().xAxis);
root.select(".y.axis")
.transition().duration(1000)
.call(chart.scales().yAxis)
.on("end", function() {
root.call(chart.zoom().transform, d3v6.zoomIdentity);
});
}


// Zoom on
function zoom_on(chart, duration) {

if (chart.settings().zoom_on === null) return;

var root = chart.svg().select(".root");
var curZoom = d3v6.zoomTransform(root.node());
var zoom_x = chart.scales().x(chart.settings().zoom_on[0]);
var zoom_y = chart.scales().y(chart.settings().zoom_on[1]);
var zoom_dx = (chart.dims().width / 2 - zoom_x) / curZoom.k;
var zoom_dy = (chart.dims().height / 2 - zoom_y) / curZoom.k;
root.transition().duration(duration)
.call(chart.zoom().translateBy, zoom_dx, zoom_dy)
.on("end", function() {
if (chart.settings().zoom_on_level != curZoom.k) {
root.transition().duration(duration)
.call(chart.zoom().scaleTo, chart.settings().zoom_on_level)
}
})

}
184 changes: 184 additions & 0 deletions docs/articles/DengueVignette_files/scatterD3-0.9.2/scatterD3.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/* TOOLTIPS */

.scatterD3-tooltip {
position: absolute;
color: #222;
background: #fff;
padding: .5em;
text-shadow: #f5f5f5 0 1px 0;
border-radius: 2px;
box-shadow: 0px 0px 7px 1px #a6a6a6;
opacity: 0.95;
font-family: Open Sans, Droid Sans, Helvetica, Verdana, sans-serif;
font-size: 10px;
z-index: 10;
}

/* GEAR MENU */

.scatterD3-menu {
position: absolute;
opacity: 0;
width: 0;
overflow: hidden;
top: 37px;
right: 15px;
z-index: 10;
background: #F5F7F9;
box-shadow: 0px 0px 2px 1px #d6d6d6;
font-family: Open Sans, Droid Sans, Helvetica, Verdana, sans-serif;
font-size: 11px;
text-align: right;
list-style: none;
padding: 0.2em;
margin: 0;
}

.scatterD3-menu li {
white-space: nowrap;
padding: 0.6em 0.8em;
margin: 0;
}

.scatterD3-menu li a {
cursor: pointer;
color: #727476;
/* font-weight: 600; */
text-decoration: none;
text-transform: uppercase;
}

.scatterD3-menu li a:hover {
color: #25282A;
}

/* GEAR ICON */

.scatterD3 .gear-menu {
cursor: pointer;
height: 25px;
width: 25px;
}

.scatterD3 .gear-menu path {
opacity: 0.2;
transition: opacity .3s;
}

.scatterD3 .gear-menu:hover path,
.scatterD3 .gear-menu.selected path {
opacity: 0.8;
transition: opacity .3s;
}

/* CAPTION */

.scatterD3-caption {
background: #F5F7F9;
color: #727476;
box-shadow: 0px 0px 2px 1px #d6d6d6;
font-family: Open Sans, Droid Sans, Helvetica, Verdana, sans-serif;
font-size: 1px;
text-align: left;
padding: 10px 0;
margin: 0;
position: absolute;
z-index: 10;
width: 100%;
transition: all .3s;
opacity: 0;
}

.scatterD3-caption.visible {
opacity: 0.97;
cursor: pointer;
}

.scatterD3-caption h1,
.scatterD3-caption h2,
.scatterD3-caption p
{
margin: 5px 15px;
line-height: 1.35;
padding: 0;
border: none;
}

.scatterD3-caption h1 {
font-size: 14px;
font-weight: bold;
}

.scatterD3-caption h2 {
font-size: 13px;
font-weight: normal;
}

.scatterD3-caption .caption {
font-size: 11px;
font-weight: normal;
}

/* CAPTION ICON */

.scatterD3 .caption-icon {
cursor: pointer;
height: 25px;
width: 25px;
}

.scatterD3 .caption-icon path {
opacity: 0.2;
transition: opacity .3s;
}

.scatterD3 .caption-icon:hover path,
.scatterD3 .caption-icon.selected path {
opacity: 0.8;
transition: opacity .3s;
}



/* OTHER STYLES */

.hidden {
display: none;
}

.scatterD3 .dot {
cursor: default;
}

.scatterD3 .point-label {
cursor: pointer;
paint-order: stroke;
stroke-width: 4px;
stroke: #FFFFFF;
}

.scatterD3, .scatterD3:focus {
outline: 0px solid transparent
}

.scatterD3 .root {
cursor: move;
}

.scatterD3 .x-axis-label,
.scatterD3 .y-axis-label {
paint-order: stroke;
stroke-width: 5px;
stroke: #FFFFFF;
}

/* Specific styles for shiny apps */

.shiny-bound-output .label {
font-size: 100%;
font-weight: normal;
text-align: left;
}



549 changes: 549 additions & 0 deletions docs/articles/DengueVignette_files/scatterD3-0.9.2/scatterD3.js

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions docs/articles/DengueVignette_files/scatterD3-0.9.2/scatterD3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
dependencies:
- name: d3v6
version: 6.2.0
src: htmlwidgets/lib/d3
script:
- d3.v6.min.js
- d3-legend.min.js
- d3-labeler.js
- name: d3.lasso-plugin
version: 1.0.0
src: htmlwidgets/lib/d3-lasso-plugin
script: lasso.js
stylesheet: lasso.css
- name: scatterD3
version: 0.9.2
src: htmlwidgets/
stylesheet: scatterD3.css
script:
- scatterD3-utils.js
- scatterD3-scales.js
- scatterD3-dims.js
- scatterD3-menu.js
- scatterD3-axes.js
- scatterD3-dots.js
- scatterD3-arrows.js
- scatterD3-labels.js
- scatterD3-labels-lines.js
- scatterD3-lines.js
- scatterD3-ellipses.js
- scatterD3-zoom.js
- scatterD3-legend.js
- scatterD3-lasso.js
- scatterD3-exports.js

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions docs/articles/TransmissionTreesVignette.html
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
// be compatible with the behavior of Pandoc < 2.8).
document.addEventListener('DOMContentLoaded', function(e) {
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
var i, h, a;
for (i = 0; i < hs.length; i++) {
h = hs[i];
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
a = h.attributes;
while (a.length > 0) h.removeAttribute(a[0].name);
}
});
6 changes: 3 additions & 3 deletions docs/articles/index.html
4,407 changes: 20 additions & 4,387 deletions docs/articles/introduction.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions docs/articles/introduction_files/d3.lasso-plugin-1.0.0/lasso.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
d3v5.lasso = function() {
d3v6.lasso = function() {

var items = null,
closePathDistance = 75,
Expand Down Expand Up @@ -57,16 +57,16 @@ d3v5.lasso = function() {
var path_length_start;

// Apply drag behaviors
var drag = d3v5.drag()
var drag = d3v6.drag()
.on("start", dragstart)
.on("drag", dragmove)
.on("end", dragend);

// Init DOM-local data
var right_edges = d3v5.local();
var left_edges = d3v5.local();
var close_right_edges = d3v5.local();
var close_left_edges = d3v5.local();
var right_edges = d3v6.local();
var left_edges = d3v6.local();
var close_right_edges = d3v6.local();
var close_left_edges = d3v6.local();

// Call drag
area.call(drag);
Expand Down Expand Up @@ -102,21 +102,21 @@ d3v5.lasso = function() {
if(hoverSelect===true) {
items.on("mouseover.lasso",function() {
// if hovered, change lasso selection attribute to true
d3v5.select(this).hoverSelected = true;
d3v6.select(this).hoverSelected = true;
});
}

// Run user defined start function
on.start();
}

function dragmove() {
function dragmove(event) {
// Get mouse position within body, used for calculations
var x = d3v5.event.sourceEvent.clientX;
var y = d3v5.event.sourceEvent.clientY;
var x = event.sourceEvent.clientX;
var y = event.sourceEvent.clientY;
// Get mouse position within drawing area, used for rendering
var tx = d3v5.mouse(this)[0];
var ty = d3v5.mouse(this)[1];
var tx = d3v6.pointer(event, this)[0];
var ty = d3v6.pointer(event, this)[1];

// Initialize the path or add the latest point to it
if (path==="") {
Expand Down Expand Up @@ -313,7 +313,7 @@ d3v5.lasso = function() {
if (!arguments.length) return items;
items = _;
items.each(function(d) {
var item = d3v5.select(this);
var item = d3v6.select(this);
if(typeof item.datum() === 'undefined') {
item.datum({possible:false,selected:false});
}
Expand Down
26 changes: 26 additions & 0 deletions docs/articles/introduction_files/d3v6-6.2.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2010-2015, Michael Bostock
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
304 changes: 304 additions & 0 deletions docs/articles/introduction_files/d3v6-6.2.0/d3-labeler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
(function() {

d3v6.labeler = function() {
var lab = [],
anc = [],
w = 1, // box width
h = 1, // box width
labeler = {};

var max_move = 15.0,
max_angle = 2,
acc = 0,
rej = 0;

// weights
var w_len = 0.1, // leader line length
w_inter = 30.0, // leader line intersection
w_lab2 = 30.0, // label-label overlap
w_lab_anc = 30.0; // label-anchor overlap
w_line_lab = 30.0; // line-label overlap
w_orient = 0.2; // orientation bias

// booleans for user defined functions
var user_energy = false,
user_schedule = false;

var user_defined_energy,
user_defined_schedule;

energy = function(index) {
// energy function, tailored for label placement

var m = lab.length,
ener = 0,
dx = lab[index].x - anc[index].x,
dy = anc[index].y - lab[index].y,
dist = Math.sqrt(dx * dx + dy * dy),
overlap = true,
amount = 0,
theta = 0;

// penalty for length of leader line
if (dist > 0) ener += dist * w_len;

// label orientation bias
dx /= dist;
dy /= dist;
if (dy < 0) { ener += w_orient; }
// if (dx > 0 && dy > 0) { ener += 0 * w_orient; }
// else if (dx < 0 && dy > 0) { ener += 1 * w_orient; }
// else if (dx < 0 && dy < 0) { ener += 2 * w_orient; }
// else { ener += 3 * w_orient; }

var x21 = lab[index].x - lab[index].width / 2,
y21 = lab[index].y - 3 * lab[index].height / 4 - 2,
x22 = lab[index].x + lab[index].width / 2,
y22 = lab[index].y + lab[index].height / 4 - 2;
var x11, x12, y11, y12, x_overlap, y_overlap, overlap_area;

for (var i = 0; i < m; i++) {
if (i != index) {

// penalty for intersection of leader lines
overlap = intersect(anc[index].x, lab[index].x, anc[i].x, lab[i].x,
anc[index].y, lab[index].y, anc[i].y, lab[i].y);
if (overlap) ener += w_inter;

// penalty for label-label overlap
x11 = lab[i].x - lab[i].width / 2 - 2;
y11 = lab[i].y - 3 * lab[i].height / 4 - 2;
x12 = lab[i].x + lab[i].width / 2 + 2;
y12 = lab[i].y + lab[i].height / 4 + 2;
x_overlap = Math.max(0, Math.min(x12,x22) - Math.max(x11,x21));
y_overlap = Math.max(0, Math.min(y12,y22) - Math.max(y11,y21));
overlap_area = x_overlap * y_overlap;
ener += (overlap_area * w_lab2);

// penalty for line-label overlap
overlap = intersect(anc[index].x, lab[index].x, x11, x12,
anc[index].y, lab[index].y, y11, y11) ||
intersect(anc[index].x, lab[index].x, x11, x11,
anc[index].y, lab[index].y, y11, y12) ||
intersect(anc[index].x, lab[index].x, x11, x12,
anc[index].y, lab[index].y, y12, y12) ||
intersect(anc[index].x, lab[index].x, x12, x12,
anc[index].y, lab[index].y, y11, y12) ||
intersect(anc[i].x, lab[i].x, x21, x22,
anc[i].y, lab[i].y, y21, y21) ||
intersect(anc[i].x, lab[i].x, x21, x21,
anc[i].y, lab[i].y, y21, y22) ||
intersect(anc[i].x, lab[i].x, x21, x22,
anc[i].y, lab[i].y, y22, y22) ||
intersect(anc[i].x, lab[i].x, x22, x22,
anc[i].y, lab[i].y, y21, y22);
if (overlap) ener += w_line_lab;
}

// penalty for label-anchor overlap
x11 = anc[i].x - anc[i].r;
y11 = anc[i].y - anc[i].r;
x12 = anc[i].x + anc[i].r;
y12 = anc[i].y + anc[i].r;
x_overlap = Math.max(0, Math.min(x12,x22) - Math.max(x11,x21));
y_overlap = Math.max(0, Math.min(y12,y22) - Math.max(y11,y21));
overlap_area = x_overlap * y_overlap;
ener += (overlap_area * w_lab_anc);



}
return ener;
};

mcmove = function(currT) {
// Monte Carlo translation move

// select a random label
var i = Math.floor(Math.random() * lab.length);

// save old coordinates
var x_old = lab[i].x;
var y_old = lab[i].y;

// old energy
var old_energy;
if (user_energy) {old_energy = user_defined_energy(i, lab, anc)}
else {old_energy = energy(i)}

// random translation
lab[i].x += (Math.random() - 0.5) * max_move;
lab[i].y += (Math.random() - 0.5) * max_move;

// hard wall boundaries
if (lab[i].x > w) lab[i].x = x_old;
if (lab[i].x < 0) lab[i].x = x_old;
if (lab[i].y > h) lab[i].y = y_old;
if (lab[i].y < 0) lab[i].y = y_old;

// new energy
var new_energy;
if (user_energy) {new_energy = user_defined_energy(i, lab, anc)}
else {new_energy = energy(i)}

// delta E
var delta_energy = new_energy - old_energy;

if (Math.random() < Math.exp(-delta_energy / currT)) {
acc += 1;
} else {
// move back to old coordinates
lab[i].x = x_old;
lab[i].y = y_old;
rej += 1;
}

};

mcrotate = function(currT) {
// Monte Carlo rotation move

// select a random label
var i = Math.floor(Math.random() * lab.length);

// save old coordinates
var x_old = lab[i].x;
var y_old = lab[i].y;

// old energy
var old_energy;
if (user_energy) {old_energy = user_defined_energy(i, lab, anc)}
else {old_energy = energy(i)}

// random angle
var angle = (Math.random() - 0.5) * max_angle;

var s = Math.sin(angle);
var c = Math.cos(angle);

// translate label (relative to anchor at origin):
lab[i].x -= anc[i].x
lab[i].y -= anc[i].y

// rotate label
var x_new = lab[i].x * c - lab[i].y * s,
y_new = lab[i].x * s + lab[i].y * c;

// translate label back
lab[i].x = x_new + anc[i].x
lab[i].y = y_new + anc[i].y

// hard wall boundaries
if (lab[i].x > w) lab[i].x = x_old;
if (lab[i].x < 0) lab[i].x = x_old;
if (lab[i].y > h) lab[i].y = y_old;
if (lab[i].y < 0) lab[i].y = y_old;

// new energy
var new_energy;
if (user_energy) {new_energy = user_defined_energy(i, lab, anc)}
else {new_energy = energy(i)}

// delta E
var delta_energy = new_energy - old_energy;

if (Math.random() < Math.exp(-delta_energy / currT)) {
acc += 1;
} else {
// move back to old coordinates
lab[i].x = x_old;
lab[i].y = y_old;
rej += 1;
}

};

intersect = function(x1, x2, x3, x4, y1, y2, y3, y4) {
// returns true if two lines intersect, else false
// from http://paulbourke.net/geometry/lineline2d/

var mua, mub;
var denom, numera, numerb;

denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);

/* Is the intersection along the the segments */
mua = numera / denom;
mub = numerb / denom;
if (!(mua < 0 || mua > 1 || mub < 0 || mub > 1)) {
return true;
}
return false;
}

cooling_schedule = function(currT, initialT, nsweeps) {
// linear cooling
return (currT - (initialT / nsweeps));
}

labeler.start = function(nsweeps) {
// main simulated annealing function
var m = lab.length,
currT = 1.0,
initialT = 1.0;
for (var i = 0; i < nsweeps; i++) {
for (var j = 0; j < m; j++) {
//mcmove(currT);
if (Math.random() < 0.5) { mcmove(currT); }
else { mcrotate(currT); }
}
currT = cooling_schedule(currT, initialT, nsweeps);
}
};

labeler.width = function(x) {
// users insert graph width
if (!arguments.length) return w;
w = x;
return labeler;
};

labeler.height = function(x) {
// users insert graph height
if (!arguments.length) return h;
h = x;
return labeler;
};

labeler.label = function(x) {
// users insert label positions
if (!arguments.length) return lab;
lab = x;
return labeler;
};

labeler.anchor = function(x) {
// users insert anchor positions
if (!arguments.length) return anc;
anc = x;
return labeler;
};

labeler.alt_energy = function(x) {
// user defined energy
if (!arguments.length) return energy;
user_defined_energy = x;
user_energy = true;
return labeler;
};

labeler.alt_schedule = function(x) {
// user defined cooling_schedule
if (!arguments.length) return cooling_schedule;
user_defined_schedule = x;
user_schedule = true;
return labeler;
};

return labeler;
};

})();

3 changes: 3 additions & 0 deletions docs/articles/introduction_files/d3v6-6.2.0/d3-legend.min.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/articles/introduction_files/d3v6-6.2.0/d3.v6.min.js

Large diffs are not rendered by default.

Binary file modified docs/articles/introduction_files/figure-html/distances-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/articles/introduction_files/figure-html/distances-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/articles/introduction_files/figure-html/plotgroves-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/articles/introduction_files/figure-html/woodmiceCluster1-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/articles/introduction_files/figure-html/woodmiceMedian-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions docs/articles/introduction_files/header-attrs-2.7/header-attrs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
// be compatible with the behavior of Pandoc < 2.8).
document.addEventListener('DOMContentLoaded', function(e) {
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
var i, h, a;
for (i = 0; i < hs.length; i++) {
h = hs[i];
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
a = h.attributes;
while (a.length > 0) h.removeAttribute(a[0].name);
}
});
903 changes: 903 additions & 0 deletions docs/articles/introduction_files/htmlwidgets-1.5.3/htmlwidgets.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* el is the div, holding the rgl object as el.rglinstance,
which holds x as el.rglinstance.scene
x is the JSON encoded rglwidget.
*/


HTMLWidgets.widget({

name: 'rglWebGL',

type: 'output',

factory: function(el, width, height) {
el.width = width;
el.height = height;
var rgl = new rglwidgetClass(),
onchangeselection = function(e) {
for (var i = 0; i < rgl.scene.crosstalk.sel_handle.length; i++)
rgl.clearBrush(except = e.rglSubsceneId);
rgl.selection(e, false);
},
onchangefilter = function(e) {
rgl.selection(e, true);
};

return {
renderValue: function(x) {
var i, pel, player, groups,
inShiny = (typeof Shiny !== "undefined");

x.crosstalk.group = groups = [].concat(x.crosstalk.group);
x.crosstalk.id = [].concat(x.crosstalk.id);
x.crosstalk.key = [].concat(x.crosstalk.key);
x.crosstalk.sel_handle = new Array(groups.length);
x.crosstalk.fil_handle = new Array(groups.length);
x.crosstalk.selection = [];
for (i = 0; i < groups.length; i++) {
x.crosstalk.sel_handle[i] = new crosstalk.SelectionHandle(groups[i], {sharedId: x.crosstalk.id[i]});
x.crosstalk.sel_handle[i].on("change", onchangeselection);
x.crosstalk.fil_handle[i] = new crosstalk.FilterHandle(groups[i], {sharedId: x.crosstalk.id[i]});
x.crosstalk.fil_handle[i].on("change", onchangefilter);
}
if (inShiny) {
// Shiny calls this multiple times, so we need extra cleanup
// between
rgl.sphere = undefined;
}
rgl.initialize(el, x);
rgl.initGL();

/* We might have been called after (some of) the players were rendered.
We need to make sure we respond to their initial values. */

if (typeof x.players !== "undefined") {
var players = [].concat(x.players);
for (i = 0; i < players.length; i++) {
pel = document.getElementById(players[i]);
if (pel) {
player = pel.rglPlayer;
if (player && (!player.initialized || inShiny)) {
rgl.Player(pel, player);
player.initialized = true;
}
}
}
}
rgl.drag = 0;
rgl.drawScene();
},

resize: function(width, height) {
el.width = width;
el.height = height;
el.rglinstance.resize(el);
el.rglinstance.drawScene();
}
};
}
});

Large diffs are not rendered by default.

967 changes: 967 additions & 0 deletions docs/articles/introduction_files/rglwidgetClass-0.105.22/draw.src.js

Large diffs are not rendered by default.

1,030 changes: 1,030 additions & 0 deletions docs/articles/introduction_files/rglwidgetClass-0.105.22/init.src.js

Large diffs are not rendered by default.

446 changes: 446 additions & 0 deletions docs/articles/introduction_files/rglwidgetClass-0.105.22/mouse.src.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// These functions order the centers of displayed objects so they
// can be drawn using the painters algorithm, necessary to support
// transparency.

// Note that objid is not obj.id when drawing spheres.

rglwidgetClass.prototype.getPieces = function(context, objid, subid, obj) {
var n = obj.centers.length,
depth,
result = new Array(n),
z, w, i;
context = context.slice();

for(i=0; i<n; i++) {
z = this.prmvMatrix.m13*obj.centers[i][0] +
this.prmvMatrix.m23*obj.centers[i][1] +
this.prmvMatrix.m33*obj.centers[i][2] +
this.prmvMatrix.m43;
w = this.prmvMatrix.m14*obj.centers[i][0] +
this.prmvMatrix.m24*obj.centers[i][1] +
this.prmvMatrix.m34*obj.centers[i][2] +
this.prmvMatrix.m44;
depth = z/w;
result[i] = {context: context,
objid: objid,
subid: subid,
index: i,
depth: depth};
}
return result;
};

rglwidgetClass.prototype.getSpherePieces = function(context, subid, obj)
{
if (obj.fastTransparency)
if (subid === 0) // Only compute pieces once
return this.getPieces(context, obj.id, -1, obj);
else
return [];
else
return this.getPieces(context, obj.id, subid, this.sphere);
};

rglwidgetClass.prototype.mergePieces = function(pieces) {
var result = [];
if (pieces.length > 0) {
var i,
thiscontext = pieces[0].context,
thisobjid = pieces[0].objid,
thissubid = pieces[0].subid,
indices = [];
for (i= 0; i < pieces.length; i++) {
if (pieces[i].context !== thiscontext ||
pieces[i].objid !== thisobjid ||
pieces[i].subid !== thissubid) {
result.push({context: thiscontext, objid: thisobjid,
subid: thissubid, indices: indices});
thiscontext = pieces[i].context;
thisobjid = pieces[i].objid;
thissubid = pieces[i].subid;
indices = [];
}
indices.push(pieces[i].index);
}
result.push({context: thiscontext, objid: thisobjid,
subid: thissubid,
indices: indices});
}
return result;
};

rglwidgetClass.prototype.sortPieces = function(pieces) {
var compare = function(i,j) {
var diff = j.depth - i.depth;
// We want to avoid context or obj changes,
// so sort on those next.
if (diff === 0) {
var c1 = j.context.slice(),
c2 = i.context.slice();
diff = c1.length - c2.length;
while (diff === 0 && c1.length > 0) {
diff = c1.pop() - c2.pop();
}
if (diff === 0)
diff = j.objid - i.objid;
if (diff === 0)
diff = j.subid - i.subid;
}
return diff;
}, result = [];
if (pieces.length)
result = pieces.sort(compare);
return result;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@

/**
* Get the viewport
*/

rglwidgetClass.prototype.getViewport = function(id) {
var vp = this.getObj(id).par3d.viewport,
x = vp.x*this.canvas.width,
y = vp.y*this.canvas.height,
width = vp.width*this.canvas.width,
height = vp.height*this.canvas.height;
this.vp = {x:x, y:y, width:width, height:height};
};

/**
* Set the gl viewport and scissor test
* @param { number } id - id of subscene
*/
rglwidgetClass.prototype.setViewport = function(id) {
var gl = this.gl || this.initGL();
this.getViewport(id);
gl.viewport(this.vp.x, this.vp.y, this.vp.width, this.vp.height);
gl.scissor(this.vp.x, this.vp.y, this.vp.width, this.vp.height);
gl.enable(gl.SCISSOR_TEST);
};

/**
* Set the projection matrix for a subscene
* @param { number } id - id of subscene
*/
rglwidgetClass.prototype.setprMatrix = function(id) {
var subscene = this.getObj(id),
embedding = subscene.embeddings.projection;
if (embedding === "replace")
this.prMatrix.makeIdentity();
else
this.setprMatrix(subscene.parent);
if (embedding === "inherit")
return;
// This is based on the Frustum::enclose code from geom.cpp
var bbox = subscene.par3d.bbox,
scale = subscene.par3d.scale,
ranges = [(bbox[1]-bbox[0])*scale[0]/2,
(bbox[3]-bbox[2])*scale[1]/2,
(bbox[5]-bbox[4])*scale[2]/2],
radius = Math.sqrt(this.sumsq(ranges))*1.1; // A bit bigger to handle labels
if (radius <= 0) radius = 1;
var observer = subscene.par3d.observer,
distance = observer[2],
FOV = subscene.par3d.FOV, ortho = FOV === 0,
t = ortho ? 1 : Math.tan(FOV*Math.PI/360),
near = distance - radius,
far = distance + radius,
hlen,
aspect = this.vp.width/this.vp.height,
z = subscene.par3d.zoom,
userProjection = subscene.par3d.userProjection;
if (far < 0.0)
far = 1.0;
if (near < far/100.0)
near = far/100.0;
this.frustum = {near:near, far:far};
hlen = t*near;
if (ortho) {
if (aspect > 1)
this.prMatrix.ortho(-hlen*aspect*z, hlen*aspect*z,
-hlen*z, hlen*z, near, far);
else
this.prMatrix.ortho(-hlen*z, hlen*z,
-hlen*z/aspect, hlen*z/aspect,
near, far);
} else {
if (aspect > 1)
this.prMatrix.frustum(-hlen*aspect*z, hlen*aspect*z,
-hlen*z, hlen*z, near, far);
else
this.prMatrix.frustum(-hlen*z, hlen*z,
-hlen*z/aspect, hlen*z/aspect,
near, far);
}
this.prMatrix.multRight(userProjection);
};

/**
* Set the model-view matrix for a subscene
* @param { number } id - id of the subscene
*/
rglwidgetClass.prototype.setmvMatrix = function(id) {
var observer = this.getObj(id).par3d.observer;
this.mvMatrix.makeIdentity();
this.setmodelMatrix(id);
this.mvMatrix.translate(-observer[0], -observer[1], -observer[2]);

};

/**
* Set the model matrix for a subscene
* @param { number } id - id of the subscene
*/
rglwidgetClass.prototype.setmodelMatrix = function(id) {
var subscene = this.getObj(id),
embedding = subscene.embeddings.model;
if (embedding !== "inherit") {
var scale = subscene.par3d.scale,
bbox = subscene.par3d.bbox,
center = [(bbox[0]+bbox[1])/2,
(bbox[2]+bbox[3])/2,
(bbox[4]+bbox[5])/2];
this.mvMatrix.translate(-center[0], -center[1], -center[2]);
this.mvMatrix.scale(scale[0], scale[1], scale[2]);
this.mvMatrix.multRight( subscene.par3d.userMatrix );
}
if (embedding !== "replace")
this.setmodelMatrix(subscene.parent);
};

/**
* Set the normals matrix for a subscene
* @param { number } subsceneid - id of the subscene
*/
rglwidgetClass.prototype.setnormMatrix = function(subsceneid) {
var self = this,
recurse = function(id) {
var sub = self.getObj(id),
embedding = sub.embeddings.model;
if (embedding !== "inherit") {
var scale = sub.par3d.scale;
self.normMatrix.scale(1/scale[0], 1/scale[1], 1/scale[2]);
self.normMatrix.multRight(sub.par3d.userMatrix);
}
if (embedding !== "replace")
recurse(sub.parent);
};
self.normMatrix.makeIdentity();
recurse(subsceneid);
};

/**
* Set the combined projection-model-view matrix
*/
rglwidgetClass.prototype.setprmvMatrix = function() {
this.prmvMatrix = new CanvasMatrix4( this.mvMatrix );
this.prmvMatrix.multRight( this.prMatrix );
};

21 changes: 21 additions & 0 deletions docs/articles/introduction_files/rglwidgetClass-0.105.22/rgl.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.rglPlayer {
width: auto;
height: auto;
}

.rglPlayer .rgl-button {
width: auto;
display: inline-block;
font-size: 75%;
}

.rglPlayer .rgl-slider {
display: inline-block;
width: 30%;
}

.rglPlayer .rgl-label {
display: inline;
padding-left: 6px;
padding-right: 6px;
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//// To generate the help pages for this library, use

// jsdoc --destination ../../../doc/rglwidgetClass --template ~/node_modules/jsdoc-baseline rglClass.src.js

// To validate, set environment variable RGL_DEBUGGING=true
// before building.

/* globals rglwidgetClass: true */

/**
* The class of an rgl widget
* @class
*/
rglwidgetClass = function() {
this.canvas = null;
this.userMatrix = new CanvasMatrix4();
this.types = [];
this.prMatrix = new CanvasMatrix4();
this.mvMatrix = new CanvasMatrix4();
this.vp = null;
this.prmvMatrix = null;
this.origs = null;
this.gl = null;
this.scene = null;
this.select = {state: "inactive", subscene: null, region: {p1: {x:0, y:0}, p2: {x:0, y:0}}};
this.drawing = false;
};


rglwidgetClass.prototype.f_is_lit = 1;
rglwidgetClass.prototype.f_is_smooth = 2;
rglwidgetClass.prototype.f_has_texture = 4;
rglwidgetClass.prototype.f_depth_sort = 8;
rglwidgetClass.prototype.f_fixed_quads = 16;
rglwidgetClass.prototype.f_is_transparent = 32;
rglwidgetClass.prototype.f_is_lines = 64;
rglwidgetClass.prototype.f_sprites_3d = 128;
rglwidgetClass.prototype.f_is_subscene = 256;
rglwidgetClass.prototype.f_is_clipplanes = 512;
rglwidgetClass.prototype.f_fixed_size = 1024;
rglwidgetClass.prototype.f_is_points = 2048;
rglwidgetClass.prototype.f_is_twosided = 4096;
rglwidgetClass.prototype.f_fat_lines = 8192;
rglwidgetClass.prototype.f_is_brush = 16384;
rglwidgetClass.prototype.f_has_fog = 32768;

rglwidgetClass.prototype.fogNone = 0;
rglwidgetClass.prototype.fogLinear = 1;
rglwidgetClass.prototype.fogExp = 2;
rglwidgetClass.prototype.fogExp2 = 3;

/**
* Start the writeWebGL scene. This is only used by writeWebGL; rglwidget has
no debug element and does the drawing in rglwidget.js.
*/
rglwidgetClass.prototype.start = function() {
if (typeof this.prefix !== "undefined") {
this.debugelement = document.getElementById(this.prefix + "debug");
this.debug("");
}
this.drag = 0;
this.drawScene();
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/* globals rgltimerClass: true */

/**
* The class of an rgl timer object
* @class
*/

/**
* Construct an rgltimerClass object
* @constructor
* @param { function } Tick - action when timer fires
* @param { number } startTime - nominal start time in seconds
* @param { number } interval - seconds between updates
* @param { number } stopTime - nominal stop time in seconds
* @param { number } stepSize - nominal step size
* @param { number } value - current nominal time
* @param { number } rate - nominal units per second
* @param { string } loop - "none", "cycle" or "oscillate"
* @param { Object } actions - list of actions
*/
rgltimerClass = function(Tick, startTime, interval, stopTime, stepSize, value, rate, loop, actions) {
this.enabled = false;
this.timerId = 0;
/** nominal start time in seconds */
this.startTime = startTime;
/** current nominal time */
this.value = value;
/** seconds between updates */
this.interval = interval;
/** nominal stop time */
this.stopTime = stopTime;
/** nominal step size */
this.stepSize = stepSize;
/** nominal units per second */
this.rate = rate;
/** "none", "cycle", or "oscillate" */
this.loop = loop;
/** real world start time */
this.realStart = undefined;
/** multiplier for fast-forward or reverse */
this.multiplier = 1;
this.actions = actions;
this.Tick = Tick;
};

/**
* Start playing timer object
*/
rgltimerClass.prototype.play = function() {
if (this.enabled) {
this.enabled = false;
window.clearInterval(this.timerId);
this.timerId = 0;
return;
}
var tick = function(self) {
var now = new Date();
self.value = self.multiplier*self.rate*(now - self.realStart)/1000 + self.startTime;
self.forceToRange();
if (typeof self.Tick !== "undefined") {
self.Tick(self.value);
}

};
this.realStart = new Date() - 1000*(this.value - this.startTime)/this.rate/this.multiplier;
this.timerId = window.setInterval(tick, 1000*this.interval, this);
this.enabled = true;
};

/**
* Force value into legal range
*/
rgltimerClass.prototype.forceToRange = function() {
if (this.value > this.stopTime + this.stepSize/2 || this.value < this.startTime - this.stepSize/2) {
if (!this.loop) {
this.reset();
} else {
var cycle = this.stopTime - this.startTime + this.stepSize,
newval = (this.value - this.startTime) % cycle + this.startTime;
if (newval < this.startTime) {
newval += cycle;
}
this.realStart += (this.value - newval)*1000/this.multiplier/this.rate;
this.value = newval;
}
}
};

/**
* Reset to start values
*/
rgltimerClass.prototype.reset = function() {
this.value = this.startTime;
this.newmultiplier(1);
if (typeof this.Tick !== "undefined") {
this.Tick(this.value);
}
if (this.enabled)
this.play(); /* really pause... */
if (typeof this.PlayButton !== "undefined")
this.PlayButton.value = "Play";
};

/**
* Increase the multiplier to play faster
*/
rgltimerClass.prototype.faster = function() {
this.newmultiplier(Math.SQRT2*this.multiplier);
};

/**
* Decrease the multiplier to play slower
*/
rgltimerClass.prototype.slower = function() {
this.newmultiplier(this.multiplier/Math.SQRT2);
};

/**
* Change sign of multiplier to reverse direction
*/
rgltimerClass.prototype.reverse = function() {
this.newmultiplier(-this.multiplier);
};

/**
* Set multiplier for play speed
* @param { number } newmult - new value
*/
rgltimerClass.prototype.newmultiplier = function(newmult) {
if (newmult !== this.multiplier) {
this.realStart += 1000*(this.value - this.startTime)/this.rate*(1/this.multiplier - 1/newmult);
this.multiplier = newmult;
}
};

/**
* Take one step
*/
rgltimerClass.prototype.step = function() {
this.value += this.rate*this.multiplier;
this.forceToRange();
if (typeof this.Tick !== "undefined")
this.Tick(this.value);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@

/**
* Respond to brush change
*/
rglwidgetClass.prototype.selectionChanged = function() {
var i, j, k, id, subid = this.select.subscene, subscene,
objids, obj,
p1 = this.select.region.p1, p2 = this.select.region.p2,
filter, selection = [], handle, keys, xmin, x, xmax, ymin, y, ymax, z, v,
someHidden;
if (!subid)
return;
subscene = this.getObj(subid);
objids = subscene.objects;
filter = this.scene.crosstalk.filter;
this.setmvMatrix(subid);
this.setprMatrix(subid);
this.setprmvMatrix();
xmin = Math.min(p1.x, p2.x);
xmax = Math.max(p1.x, p2.x);
ymin = Math.min(p1.y, p2.y);
ymax = Math.max(p1.y, p2.y);
for (i = 0; i < objids.length; i++) {
id = objids[i];
j = this.scene.crosstalk.id.indexOf(id);
if (j >= 0) {
keys = this.scene.crosstalk.key[j];
obj = this.getObj(id);
someHidden = false;
for (k = 0; k < keys.length; k++) {
if (filter && filter.indexOf(keys[k]) < 0) {
someHidden = true;
continue;
}
v = [].concat(obj.vertices[k]).concat(1.0);
v = this.multVM(v, this.prmvMatrix);
x = v[0]/v[3];
y = v[1]/v[3];
z = v[2]/v[3];
if (xmin <= x && x <= xmax && ymin <= y && y <= ymax && -1.0 <= z && z <= 1.0) {
selection.push(keys[k]);
} else
someHidden = true;
}
obj.someHidden = someHidden && (filter || selection.length);
obj.initialized = false;
/* Who should we notify? Only shared data in the current subscene, or everyone? */
if (!this.equalArrays(selection, this.scene.crosstalk.selection)) {
handle = this.scene.crosstalk.sel_handle[j];
handle.set(selection, {rglSubsceneId: this.select.subscene});
}
}
}
};

/**
* Respond to selection or filter change from crosstalk
* @param { Object } event - crosstalk event
* @param { boolean } filter - filter or selection?
*/
rglwidgetClass.prototype.selection = function(event, filter) {
var i, j, ids, obj, keys, crosstalk = this.scene.crosstalk,
selection, someHidden;

// Record the message and find out if this event makes some objects have mixed values:

crosstalk = this.scene.crosstalk;

if (filter) {
filter = crosstalk.filter = event.value;
selection = crosstalk.selection;
} else {
selection = crosstalk.selection = event.value;
filter = crosstalk.filter;
}
ids = crosstalk.id;
for (i = 0; i < ids.length ; i++) {
obj = this.getObj(ids[i]);
obj.initialized = false;
keys = crosstalk.key[i];
someHidden = false;
for (j = 0; j < keys.length && !someHidden; j++) {
if ((filter && filter.indexOf(keys[j]) < 0) ||
(selection.length && selection.indexOf(keys[j]) < 0))
someHidden = true;
}
obj.someHidden = someHidden;
}
this.drawScene();
};

/**
* Clear the selection brush
* @param { number } except - Subscene that should ignore this request
*/
rglwidgetClass.prototype.clearBrush = function(except) {
if (this.select.subscene !== except) {
this.select.region = {p1: {x:Infinity, y:Infinity},
p2: {x:Infinity, y:Infinity}};
this.selectionChanged();
this.select.state = "inactive";
this.delFromSubscene(this.scene.brushId, this.select.subscene);
}
this.drawScene();
};

/**
* Set the vertices in the selection box object
*/
rglwidgetClass.prototype.initSelection = function(id) {
if (typeof this.select.region === "undefined")
return;
var obj = this.getObj(id),
p1 = this.select.region.p1,
p2 = this.select.region.p2;

obj.vertices = [[p1.x, p1.y, 0.0],
[p2.x, p1.y, 0.0],
[p2.x, p2.y, 0.0],
[p1.x, p2.y, 0.0],
[p1.x, p1.y, 0.0]];
};

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* Is a particular id in a subscene?
* @returns { boolean }
* @param {number} id Which id?
* @param {number} subscene Which subscene id?
*/
rglwidgetClass.prototype.inSubscene = function(id, subscene) {
return this.getObj(subscene).objects.indexOf(id) > -1;
};

/**
* Translate from window coordinates to viewport coordinates
* @returns { Object } translated coordinates
* @param { number } subsceneid - which subscene to use?
* @param { Object } coords - point to translate
*/
rglwidgetClass.prototype.translateCoords = function(subsceneid, coords) {
var viewport = this.getObj(subsceneid).par3d.viewport;
return {x: coords.x - viewport.x*this.canvas.width,
y: coords.y - viewport.y*this.canvas.height};
};

/**
* Check whether point is in viewport of subscene
* @returns {boolean}
* @param { Object } coords - screen coordinates of point
* @param { number } subsceneid - subscene to check
*/
rglwidgetClass.prototype.inViewport = function(coords, subsceneid) {
var viewport = this.getObj(subsceneid).par3d.viewport,
x0 = coords.x - viewport.x*this.canvas.width,
y0 = coords.y - viewport.y*this.canvas.height;
return 0 <= x0 && x0 <= viewport.width*this.canvas.width &&
0 <= y0 && y0 <= viewport.height*this.canvas.height;
};

/**
* Find which subscene contains a point
* @returns { number } subscene id
* @param { Object } coords - coordinates of point
*/
rglwidgetClass.prototype.whichSubscene = function(coords) {
var self = this,
recurse = function(subsceneid) {
var subscenes = self.getChildSubscenes(subsceneid), i, id;
for (i=0; i < subscenes.length; i++) {
id = recurse(subscenes[i]);
if (typeof(id) !== "undefined")
return(id);
}
if (self.inViewport(coords, subsceneid))
return(subsceneid);
else
return undefined;
},
rootid = this.scene.rootSubscene,
result = recurse(rootid);
if (typeof(result) === "undefined")
result = rootid;
return result;
};

/**
* Add an id to a subscene.
* @param {number} id Which id?
* @param {number} subscene Which subscene id?
*/
rglwidgetClass.prototype.addToSubscene = function(id, subscene) {
var thelist,
thesub = this.getObj(subscene),
ids = [id],
obj = this.getObj(id), i;
if (typeof obj !== "undefined" && typeof (obj.newIds) !== "undefined") {
ids = ids.concat(obj.newIds);
}
thesub.objects = [].concat(thesub.objects);
for (i = 0; i < ids.length; i++) {
id = ids[i];
if (thesub.objects.indexOf(id) === -1) {
thelist = this.whichList(id);
thesub.objects.push(id);
thesub[thelist].push(id);
}
}
};

/**
* Delete an id from a subscene
* @param { number } id - the id to add
* @param { number } subscene - the id of the subscene
*/
rglwidgetClass.prototype.delFromSubscene = function(id, subscene) {
var thelist,
thesub = this.getObj(subscene),
obj = this.getObj(id),
ids = [id], i, j;
if (typeof obj !== "undefined" && typeof (obj.newIds) !== "undefined")
ids = ids.concat(obj.newIds);
thesub.objects = [].concat(thesub.objects); // It might be a scalar
for (j=0; j<ids.length;j++) {
id = ids[j];
i = thesub.objects.indexOf(id);
if (i > -1) {
thesub.objects.splice(i, 1);
thelist = this.whichList(id);
i = thesub[thelist].indexOf(id);
thesub[thelist].splice(i, 1);
}
}
};

/**
* Set the ids in a subscene
* @param { number[] } ids - the ids to set
* @param { number } subsceneid - the id of the subscene
*/
rglwidgetClass.prototype.setSubsceneEntries = function(ids, subsceneid) {
var sub = this.getObj(subsceneid);
sub.objects = ids;
this.initSubscene(subsceneid);
};

/**
* Get the ids in a subscene
* @returns {number[]}
* @param { number } subscene - the id of the subscene
*/
rglwidgetClass.prototype.getSubsceneEntries = function(subscene) {
return this.getObj(subscene).objects;
};

/**
* Get the ids of the subscenes within a subscene
* @returns { number[] }
* @param { number } subscene - the id of the subscene
*/
rglwidgetClass.prototype.getChildSubscenes = function(subscene) {
return this.getObj(subscene).subscenes;
};

/**
* Find a particular subscene by inheritance
* @returns { number } id of subscene to use
* @param { number } subsceneid - child subscene
* @param { string } type - type of inheritance: "projection" or "model"
*/
rglwidgetClass.prototype.useid = function(subsceneid, type) {
var sub = this.getObj(subsceneid);
if (sub.embeddings[type] === "inherit")
return(this.useid(sub.parent, type));
else
return subsceneid;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@

/**
* Handle a texture after its image has been loaded
* @param { Object } texture - the gl texture object
* @param { Object } textureCanvas - the canvas holding the image
*/
rglwidgetClass.prototype.handleLoadedTexture = function(texture, textureCanvas) {
var gl = this.gl || this.initGL();
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureCanvas);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);

gl.bindTexture(gl.TEXTURE_2D, null);
};

/**
* Get maximum dimension of texture in current browser.
* @returns {number}
*/
rglwidgetClass.prototype.getMaxTexSize = function() {
var gl = this.gl || this.initGL();
return Math.min(4096, gl.getParameter(gl.MAX_TEXTURE_SIZE));
};

/**
* Load an image to a texture
* @param { string } uri - The image location
* @param { Object } texture - the gl texture object
*/
rglwidgetClass.prototype.loadImageToTexture = function(uri, texture) {
var canvas = this.textureCanvas,
ctx = canvas.getContext("2d"),
image = new Image(),
self = this;

image.onload = function() {
var w = image.width,
h = image.height,
canvasX = self.getPowerOfTwo(w),
canvasY = self.getPowerOfTwo(h),
maxTexSize = self.getMaxTexSize();
while (canvasX > 1 && canvasY > 1 && (canvasX > maxTexSize || canvasY > maxTexSize)) {
canvasX /= 2;
canvasY /= 2;
}
canvas.width = canvasX;
canvas.height = canvasY;
ctx.imageSmoothingEnabled = true;
ctx.drawImage(image, 0, 0, canvasX, canvasY);
self.handleLoadedTexture(texture, canvas);
self.drawScene();
};
image.src = uri;
};

/**
* Draw text to the texture canvas
* @returns { Object } object with text measurements
* @param { string } text - the text
* @param { number } cex - expansion
* @param { string } family - font family
* @param { number } font - font number
*/
rglwidgetClass.prototype.drawTextToCanvas = function(text, cex, family, font) {
var canvasX, canvasY,
scaling = 20,
textColour = "white",

backgroundColour = "rgba(0,0,0,0)",
canvas = this.textureCanvas,
ctx = canvas.getContext("2d"),
i, textHeight = 0, textHeights = [], width, widths = [],
offsetx, offsety = 0, line, lines = [], offsetsx = [],
offsetsy = [], lineoffsetsy = [], fontStrings = [],
maxTexSize = this.getMaxTexSize(),
getFontString = function(i) {
textHeights[i] = scaling*cex[i];
var fontString = textHeights[i] + "px",
family0 = family[i],
font0 = font[i];
if (family0 === "sans")
family0 = "sans-serif";
else if (family0 === "mono")
family0 = "monospace";
fontString = fontString + " " + family0;
if (font0 === 2 || font0 === 4)
fontString = "bold " + fontString;
if (font0 === 3 || font0 === 4)
fontString = "italic " + fontString;
return fontString;
};
cex = this.repeatToLen(cex, text.length);
family = this.repeatToLen(family, text.length);
font = this.repeatToLen(font, text.length);

canvasX = 1;
line = -1;
offsetx = maxTexSize;
for (i = 0; i < text.length; i++) {
ctx.font = fontStrings[i] = getFontString(i);
width = widths[i] = ctx.measureText(text[i]).width;
if (offsetx + width > maxTexSize) {
offsety = offsety + 2*textHeight;
if (line >= 0)
lineoffsetsy[line] = offsety;
line += 1;
if (offsety > maxTexSize)
console.error("Too many strings for texture.");
textHeight = 0;
offsetx = 0;
}
textHeight = Math.max(textHeight, textHeights[i]);
offsetsx[i] = offsetx;
offsetx += width;
canvasX = Math.max(canvasX, offsetx);
lines[i] = line;
}
offsety = lineoffsetsy[line] = offsety + 2*textHeight;
for (i = 0; i < text.length; i++) {
offsetsy[i] = lineoffsetsy[lines[i]];
}

canvasX = this.getPowerOfTwo(canvasX);
canvasY = this.getPowerOfTwo(offsety);

canvas.width = canvasX;
canvas.height = canvasY;

ctx.fillStyle = backgroundColour;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

ctx.textBaseline = "alphabetic";
for(i = 0; i < text.length; i++) {
ctx.font = fontStrings[i];
ctx.fillStyle = textColour;
ctx.textAlign = "left";
ctx.fillText(text[i], offsetsx[i], offsetsy[i]);
}
return {canvasX:canvasX, canvasY:canvasY,
widths:widths, textHeights:textHeights,
offsetsx:offsetsx, offsetsy:offsetsy};
};

502 changes: 502 additions & 0 deletions docs/articles/introduction_files/rglwidgetClass-0.105.22/utils.src.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Copyright (c) 2015-2016, Speros Kokenes
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
lasso
=========

lasso.js is a D3 plugin that allows you to tag elements on a page by drawing a line over or around objects. Functions can be run based on the lasso action. This functionality can be useful for brushing or filtering.

An example of the lasso implemented in a scatterplot can be found here: [http://bl.ocks.org/skokenes/511c5b658c405ad68941](http://bl.ocks.org/skokenes/511c5b658c405ad68941)

This example is based off of Mike Bostock's scatterplot example here: [http://bl.ocks.org/mbostock/3887118](http://bl.ocks.org/mbostock/3887118)

Lassoing tags
--
When the lasso is used, it tags elements by adding properties to their data. The properties are:

- possible: while drawing a lasso, if an element is part of the final selection that would be made if the lasso was completed at that instance, this value is true. Otherwise, it is false.
- selected: when a lasso is completed, all elements that were tagged as possible are given a selected value of true. Otherwise, the value is false.

The tags can be used in combination with functions to perform actions like styling the possible or selected values while the lasso is in use.

Note that the lasso only works with elements whose data is defined as an object.


Function Overview
--
**d3.lasso**()

Creates a new lasso object. This object can then have parameters set before the lasso is drawn.
```
var lasso = d3.lasso(); // creates a new lasso
```

lasso.**items**(_[selection]_)

The items() parameter takes in a d3 selection. Each element in the selection will be tagged with lasso-specific properties when the lasso is used. If no input is specified, the function returns the lasso's current items.
```
lasso.items(d3.selectAll("circle")); // sets all circles on the page to be lasso-able
```

lasso.**hoverSelect**(_[bool]_)

The hoverSelect() parameter takes in a boolean that determines whether objects can be lassoed by hovering over an element during lassoing. The default value is set to true. If no input is specified, the function returns the lasso's current hover parameter.
```
lasso.hoverSelect(true); // allows hovering of elements for selection during lassoing
```

lasso.**closePathSelect**(_[bool]_)

The closePathSelect() parameter takes in a boolean that determines whether objects can be lassoed by drawing a loop around them. The default value is set to true. If no input is specified, the function returns the lasso's current parameter.
```
lasso.closePathSelect(true); // allows looping of elements for selection during lassoing
```

lasso.**closePathDistance**(_[num]_)

The closePathDistance() parameter takes in a number that specifies the maximum distance in pixels from the lasso origin that a lasso needs to be drawn in order to complete the loop and select elements. This parameter only works if closePathSelect is set to true; If no input is specified, the function returns the lasso's current parameter.
```
lasso.closePathDistance(75); // the lasso loop will complete itself whenever the lasso end is within 75 pixels of the origin
```

lasso.**area**(_[sel]_)

The area() parameter takes in a selection representing the element to be used as a target area for the lasso event. If no input is specified, the function returns the current area selection.
```
lasso.area(d3.select("#myLassoRect")); // the lasso will be trigger whenever a user clicks and drags on #myLassoRect
```

lasso.**on**(_type,[func]_)

The on() parameter takes in a type of event and a function for that event. There are 3 types of events that can be defined:
- start: this function will be executed whenever a lasso is started
- draw: this function will execute repeatedly as the lasso is drawn
- end: this function will be executed whenever a lasso is completed

If no function is specified, the function will return the current function defined for the type specified.
```
lasso.on("start",function() { alert("lasso started!"); }); // every time a lasso is started, an alert will trigger
```

Initiating a lasso
--
Once a lasso object is defined, it can be added to a page by calling it on an element like an svg.
```
var lasso = d3.lasso()
.items(d3.selectAll("circle")) // Create a lasso and provide it some target elements
.area(de.select("#myLassoRect")); // Sets the drag area for the lasso on the rectangle #myLassoRect
d3.select("svg").call(lasso); // Initiate the lasso on an svg element
```

If a lasso is going to be used on graphical elements that have been translated via a g element acting as a container, which is a common practice for incorporating chart margins, then the lasso should be called on that g element so that it is in the same coordinate system as the graphical elements.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.lasso path {
stroke: rgb(80,80,80);
stroke-width: 2px;
}

.lasso .drawn {
fill: #CCCCCC;
fill-opacity: .15 ;
}

.lasso .loop_close {
fill: none;
stroke-dasharray: 4,4;
}

.lasso .origin {
fill: #3399FF;
fill-opacity: .5;
}

.scatterD3 .not-possible-lasso {
fill: rgb(150,150,150);
opacity: 1;
}

.scatterD3 .arrow.not-possible-lasso {
stroke: rgb(200,200,200);
}

.scatterD3 .point-label-line.not-possible-lasso {
stroke: rgb(200,200,200);
}

.scatterD3 .possible-lasso {
fill: #EC888C;
opacity: 1;
}

.scatterD3 .arrow.possible-lasso {
stroke: #EC888C;
}

.scatterD3 .point-label-line.possible-lasso {
stroke: #EC888C;
}

/*.scatterD3 .selected-lasso {
opacity: 1 !important;
}
.scatterD3 .not-selected-lasso {
opacity: 0.1 !important;
}*/
Loading