Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add closed flag to line features #602

Merged
merged 2 commits into from
Aug 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions examples/picking/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/* globals utils */

// Run after the DOM loads
$(function () {
'use strict';

var query = utils.getQuery();

// Create a map object with the OpenStreetMaps base layer.
var map = geo.map({
node: '#map',
Expand Down Expand Up @@ -62,9 +66,10 @@ $(function () {
vglLayer.createFeature('line', {selectionAPI: true})
.data([window.randomPath(1000, 0.1, -88, 30), window.randomPath(500, 0.05, -110, 40)])
.style({
'strokeColor': function (d, i, e, j) { return (j % 2) ? color(0) : color(1); },
'strokeWidth': 5,
'strokeOpacity': function (d, i, e) { return e.clicked ? 1 : 0.5; }
strokeColor: function (d, i, e, j) { return (j % 2) ? color(0) : color(1); },
strokeWidth: 5,
strokeOpacity: function (d, i, e) { return e.clicked ? 1 : 0.5; },
closed: query.closed === 'true'
})
.geoOn(geo.event.feature.mouseover, handleMouseOver)
.geoOn(geo.event.feature.mouseout, handleMouseOut)
Expand All @@ -74,9 +79,10 @@ $(function () {
svgLayer.createFeature('line', {selectionAPI: true})
.data([window.randomPath(1000, 0.1, -108, 30), window.randomPath(500, 0.05, -88, 40)])
.style({
'strokeColor': function (d, i, l, j) { return (j % 2) ? color(2) : color(3); },
'strokeWidth': 5,
'strokeOpacity': function (d, i, e) { return e.clicked ? 1 : 0.5; }
strokeColor: function (d, i, l, j) { return (j % 2) ? color(2) : color(3); },
strokeWidth: 5,
strokeOpacity: function (d, i, e) { return e.clicked ? 1 : 0.5; },
closed: query.closed === 'true'
})
.geoOn(geo.event.feature.mouseover, handleMouseOver)
.geoOn(geo.event.feature.mouseout, handleMouseOut)
Expand Down
9 changes: 6 additions & 3 deletions src/d3/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ var d3_lineFeature = function (arg) {
s_style = m_this.style(),
m_renderer = m_this.renderer(),
pos_func = m_this.position(),
line = d3.svg.line()
.x(function (d) { return m_this.featureGcsToDisplay(d).x; })
.y(function (d) { return m_this.featureGcsToDisplay(d).y; });
line;

s_update.call(m_this);
s_style.fill = function () { return false; };
Expand All @@ -86,6 +84,11 @@ var d3_lineFeature = function (arg) {
}
}

line = d3.svg.line()
.x(function (d) { return m_this.featureGcsToDisplay(d).x; })
.y(function (d) { return m_this.featureGcsToDisplay(d).y; })
.interpolate(m_this.style.get('closed')(item, idx) && ln.length > 2 ?
'linear-closed' : 'linear');
// item is an object representing a single line
// m_this.line()(item) is an array of coordinates
m_style = {
Expand Down
46 changes: 35 additions & 11 deletions src/gl/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ var gl_lineFeature = function (arg) {

function createGLLines() {
var data = m_this.data(),
i, j, k, v,
i, j, k, v, lidx,
numSegments = 0, len,
lineItem, lineItemData,
vert = [{}, {}], vertTemp,
pos, posIdx3,
pos, posIdx3, firstpos, firstPosIdx3,
position = [],
posFunc = m_this.position(),
strkWidthFunc = m_this.style.get('strokeWidth'),
Expand All @@ -141,7 +141,8 @@ var gl_lineFeature = function (arg) {
posBuf, nextBuf, prevBuf, offsetBuf, indicesBuf,
strokeWidthBuf, strokeColorBuf, strokeOpacityBuf,
dest, dest3,
geom = m_mapper.geometryData();
geom = m_mapper.geometryData(),
closedFunc = m_this.style.get('closed'), closed = [];

for (i = 0; i < data.length; i += 1) {
lineItem = m_this.line()(data[i], i);
Expand All @@ -151,6 +152,19 @@ var gl_lineFeature = function (arg) {
position.push(pos.x);
position.push(pos.y);
position.push(pos.z || 0.0);
if (!j) {
firstpos = pos;
}
}
if (lineItem.length > 2 && closedFunc(data[i], i)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why passing two arguments to closedFunc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our general method of getting style information from functions is to pass two parameters: the current data item and its index.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sub-components, like points within a line, the style information is obtained by calling a function with four parameters: the current sub-item (a vertex, for instance), the sub-item's index, the current item (the line), and the item index.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our general method of getting style information from functions is to pass two parameters: the current data item and its index.

Sure, makes sense.

/* line is closed */
if (pos.x !== firstpos.x || pos.y !== firstpos.y ||
pos.z !== firstpos.z) {
numSegments += 1;
closed[i] = 2; /* first and last points are distinct */
} else {
closed[i] = 1; /* first point is repeated as last point */
}
}
}

Expand All @@ -174,21 +188,30 @@ var gl_lineFeature = function (arg) {

for (i = posIdx3 = dest = dest3 = 0; i < data.length; i += 1) {
lineItem = m_this.line()(data[i], i);
for (j = 0; j < lineItem.length; j += 1, posIdx3 += 3) {
lineItemData = lineItem[j];
firstPosIdx3 = posIdx3;
for (j = 0; j < lineItem.length + (closed[i] === 2 ? 1 : 0); j += 1, posIdx3 += 3) {
lidx = j;
if (j === lineItem.length) {
lidx = 0;
posIdx3 -= 3;
}
lineItemData = lineItem[lidx];
/* swap entries in vert so that vert[0] is the first vertex, and
* vert[1] will be reused for the second vertex */
if (j) {
vertTemp = vert[0];
vert[0] = vert[1];
vert[1] = vertTemp;
}
vert[1].pos = posIdx3;
vert[1].prev = posIdx3 - (j ? 3 : 0);
vert[1].next = posIdx3 + (j + 1 < lineItem.length ? 3 : 0);
vert[1].strokeWidth = strkWidthFunc(lineItemData, j, lineItem, i);
vert[1].strokeColor = strkColorFunc(lineItemData, j, lineItem, i);
vert[1].strokeOpacity = strkOpacityFunc(lineItemData, j, lineItem, i);
vert[1].pos = j === lidx ? posIdx3 : firstPosIdx3;
vert[1].prev = lidx ? posIdx3 - 3 : (closed[i] ?
firstPosIdx3 + (lineItem.length - 3 + closed[i]) * 3 : posIdx3);
vert[1].next = j + 1 < lineItem.length ? posIdx3 + 3 : (closed[i] ?
(j !== lidx ? firstPosIdx3 + 3 : firstPosIdx3 + 6 - closed[i] * 3) :
posIdx3);
vert[1].strokeWidth = strkWidthFunc(lineItemData, lidx, lineItem, i);
vert[1].strokeColor = strkColorFunc(lineItemData, lidx, lineItem, i);
vert[1].strokeOpacity = strkOpacityFunc(lineItemData, lidx, lineItem, i);
if (j) {
for (k = 0; k < order.length; k += 1, dest += 1, dest3 += 3) {
v = vert[order[k][0]];
Expand Down Expand Up @@ -384,6 +407,7 @@ var gl_lineFeature = function (arg) {
////////////////////////////////////////////////////////////////////////////
this._exit = function () {
m_this.renderer().contextRenderer().removeActor(m_actor);
m_actor = null;
s_exit();
};

Expand Down
41 changes: 28 additions & 13 deletions src/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ var lineFeature = function (arg) {
/**
* Returns an array of datum indices that contain the given point.
* This is a slow implementation with runtime order of the number of
* vertices.
* vertices. A point is considered on a line segment if it is close to the
* line or either end point. Closeness is based on the maximum width of the
* line segement, and is ceil(maxwidth / 2) + 2 pixels. This means that
* corner extensions due to mitering may be outside of the selection area and
* that variable width lines will have a greater selection region than their
* visual size at the narrow end.
*/
////////////////////////////////////////////////////////////////////////////
this.pointSearch = function (p) {
Expand Down Expand Up @@ -118,7 +123,8 @@ var lineFeature = function (arg) {

// for each line
data.forEach(function (d, index) {
var last = null;
var closed = m_this.style.get('closed')(d, index),
last, lastr, first;

try {
line(d, index).forEach(function (current, j) {
Expand All @@ -127,19 +133,25 @@ var lineFeature = function (arg) {
var p = pos(current, j, d, index);
var s = m_this.featureGcsToDisplay(p);
var r = Math.ceil(width(p, j, d, index) / 2) + 2;
r = r * r;

if (last) {
var r2 = lastr > r ? lastr * lastr : r * r;
// test the line segment s -> last
if (lineDist2(pt, s, last) <= r) {

if (lineDist2(pt, s, last) <= r2) {
// short circuit the loop here
throw 'found';
}
}

last = s;
lastr = r;
if (!first && closed) {
first = {s: s, r: r};
}
});
if (closed && lineDist2(pt, last, first.s) <= first.r) {
throw 'found';
}
} catch (err) {
if (err !== 'found') {
throw err;
Expand All @@ -150,7 +162,7 @@ var lineFeature = function (arg) {
});

return {
data: found,
found: found,
index: indices
};
};
Expand All @@ -168,7 +180,7 @@ var lineFeature = function (arg) {
opts = opts || {};
opts.partial = opts.partial || false;
if (opts.partial) {
throw 'Unimplemented query method.';
throw new Error('Unimplemented query method.');
}

m_this.data().forEach(function (d, i) {
Expand Down Expand Up @@ -197,18 +209,20 @@ var lineFeature = function (arg) {
*/
////////////////////////////////////////////////////////////////////////////
this._init = function (arg) {
arg = arg || {};
s_init.call(m_this, arg);

var defaultStyle = $.extend(
{},
{
'strokeWidth': 1.0,
strokeWidth: 1.0,
// Default to gold color for lines
'strokeColor': { r: 1.0, g: 0.8431372549, b: 0.0 },
'strokeStyle': 'solid',
'strokeOpacity': 1.0,
'line': function (d) { return d; },
'position': function (d) { return d; }
strokeColor: { r: 1.0, g: 0.8431372549, b: 0.0 },
strokeStyle: 'solid',
strokeOpacity: 1.0,
closed: false,
line: function (d) { return d; },
position: function (d) { return d; }
},
arg.style === undefined ? {} : arg.style
);
Expand Down Expand Up @@ -240,6 +254,7 @@ var lineFeature = function (arg) {
lineFeature.create = function (layer, spec) {
'use strict';

spec = spec || {};
spec.type = 'line';
return feature.create(layer, spec);
};
Expand Down
2 changes: 1 addition & 1 deletion src/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ var pointFeature = function (arg) {
});

return {
data: found,
found: found,
index: ifound
};
};
Expand Down
18 changes: 5 additions & 13 deletions src/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,24 +247,15 @@ var polygonFeature = function (arg) {
* @param {object} item: the polygon.
* @param {number} itemIndex: the index of the polygon
* @param {Array} loop: the inner or outer loop.
* @param {function} posFunc: a function that gets the coordinates of a
* vertex. Used to compare the first and last vertices of the polygon.
* If they do not match exactly, the first vertex is added at the end to
* close the polyline.
* @returns {Array} the loop with the data necessary to send to the position
* function for each vertex.
*/
this._getLoopData = function (item, itemIndex, loop, posFunc) {
var line = [], i, startpos, endpos;
this._getLoopData = function (item, itemIndex, loop) {
var line = [], i;

for (i = 0; i < loop.length; i += 1) {
line.push([loop[i], i, item, itemIndex]);
}
startpos = posFunc(loop[0], 0, item, itemIndex);
endpos = posFunc(loop[loop.length - 1], loop.length - 1, item, itemIndex);
if (startpos.x !== endpos.x || startpos.y !== endpos.y || startpos.z !== endpos.z) {
line.push([loop[0], 0, item, itemIndex]);
}
return line;
};

Expand All @@ -291,6 +282,7 @@ var polygonFeature = function (arg) {
}
var polyStyle = m_this.style();
m_lineFeature.style({
closed: true,
strokeWidth: polyStyle.strokeWidth,
strokeStyle: polyStyle.strokeStyle,
strokeColor: polyStyle.strokeColor,
Expand All @@ -306,10 +298,10 @@ var polygonFeature = function (arg) {
for (i = 0; i < data.length; i += 1) {
polygon = m_this.polygon()(data[i], i);
loop = polygon.outer || (polygon instanceof Array ? polygon : []);
lineData.push(m_this._getLoopData(data[i], i, loop, posFunc));
lineData.push(m_this._getLoopData(data[i], i, loop));
if (polygon.inner) {
polygon.inner.forEach(function (loop) {
lineData.push(m_this._getLoopData(data[i], i, loop, posFunc));
lineData.push(m_this._getLoopData(data[i], i, loop));
});
}
}
Expand Down
Loading