Skip to content

Commit 08dacdd

Browse files
committed
add highlight of items.
1 parent 3d1b457 commit 08dacdd

File tree

2 files changed

+164
-108
lines changed

2 files changed

+164
-108
lines changed

src/css/panel.action.css

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.select-source {
2+
outline: 5px solid rgb(0, 255, 0, 0.5);
3+
}
4+
5+
.select-target {
6+
outline: 5px solid rgb(255, 0, 0, 0.5);
7+
}
8+
9+
.select-other {
10+
outline: 5px solid rgb(255, 255, 0, 0.5);
11+
}

src/js/panel._utils.js

+153-108
Original file line numberDiff line numberDiff line change
@@ -150,124 +150,169 @@ window.Widgets.Panel.Utils = {};
150150
ns.contentMenuItem = false;
151151

152152

153-
// setup the left click capability
154-
ns.selectArray = [];
153+
// setup tracker for selection
154+
ns.selection = {
155+
list: [], // array of data objects
156+
ids: [], // array of id's matching the data objects
157+
ref: {}, // id reference to data object, for quick lookup of ref to list and ids
158+
max: 2, //posibly allow more selected items
159+
maxAction: "last", //add to bottom or top of array
160+
add: function(id, data) {
161+
if (this.maxAction === "last") {
162+
return this.popIn(id, data);
163+
} else {
164+
return this.shiftIn(id, data);
165+
}
166+
},
167+
remove: function(id, data) {
168+
const index = this.getIndexOf(id);
169+
if (index > -1) {
170+
this.list.splice(index, 1);
171+
this.ids.splice(index, 1);
172+
delete this.ref[id];
173+
}
174+
return index;
175+
},
176+
popIn: function(id, data) { // add to bottom and remove first
177+
let removedData;
178+
let removedId;
179+
if (this.isFull()) {
180+
removedData = this.list.shift(); //remove first item
181+
removedId = this.ids.shift(); //remove first item
182+
//remove reference
183+
delete this.ref[removedId];
184+
}
185+
this.list.push(data); // add last item
186+
this.ids.push(id); // add last item
187+
188+
//save id reference
189+
this.ref[id] = {
190+
d: this.list[this.list.length - 1],
191+
i: this.ids[this.ids.length - 1]
192+
};
193+
return removedData;
194+
},
195+
shiftIn: function(id, data) { // add to top and remove last
196+
let removedData;
197+
let removedId;
198+
if (this.isFull()) {
199+
removedData = this.list.pop(); //remove last item
200+
removedId = this.ids.pop(); //remove last item
201+
//remove reference
202+
delete this.ref[removedId];
203+
}
204+
this.list.unshift(data); // add first item
205+
this.ids.unshift(id); // add first item
206+
//save id reference
207+
this.ref[id] = {
208+
d: this.list[0],
209+
i: this.ids[0]
210+
};
211+
return removedData;
212+
},
213+
clear: function() {
214+
this.list = [];
215+
this.ref = {};
216+
},
217+
isFull: function() {
218+
return this.ids.length === this.max;
219+
},
220+
has: function(id) {
221+
const hasRef = this.ref[id];
222+
if (hasRef === undefined) {
223+
return false;
224+
}
225+
const hasId = this.ids.includes(id);
226+
const hasData = this.list.includes(hasRef.d);
227+
228+
if (hasId && hasData) {
229+
return true;
230+
} else {
231+
console.error("ERROR: selection data is out of sync");
232+
return false;
233+
}
234+
},
235+
count: function() {
236+
return this.ids.length;
237+
},
238+
getFirst: function() {
239+
return this.list[0];
240+
},
241+
getLast: function() {
242+
if (this.ids.length > 1) {
243+
return this.list[this.ids.length - 1];
244+
}
245+
return
246+
},
247+
getIndexOf: function(id) {
248+
//get reference to the data object
249+
const data = this.ref[id];
250+
if (data === undefined) {
251+
return -1;
252+
}
253+
console.log("data->", data);
254+
//get the index of the data object
255+
return this.ids.indexOf(data.i);
256+
}
257+
};
258+
155259
ns.leftclick = function(event, d) {
156260
console.group("Widgets.Panel.Utils.leftclick");
157261
console.log("event->", event);
158262
console.log("d->", d);
159263

160-
// Setup the local theme
161-
if (!ns.theme) {
162-
if (ns.options.theme === 'light') {
163-
ns.theme = ns.options.light_theme
164-
} else {
165-
ns.theme = ns.options.dark_theme
166-
}
264+
const selected = d3.select(this)
265+
const id = d.id;
266+
const data = {
267+
id: id,
268+
element: selected,
269+
data: d,
270+
event: event,
167271
}
168272

169-
let len = ns.selectArray.length;
170-
const selected = d3.select(this); // can't use arrow scoping
171-
console.log(`selected->`, selected);
172-
173-
if (d3.select(this).classed('clicked')) {
174-
// Toggle-off the clicked state
175-
//
176-
console.log("Branch 1 - time to toggle select");
177-
console.log("ns.selectArray->", ns.selectArray);
178-
// 1. Pop the element from the array
179-
for(var i = ns.selectArray.length - 1; i >= 0; i--){
180-
if(ns.selectArray[i].id === selected.id){
181-
ns.selectArray.splice(i, 1);
182-
}
183-
}
184-
// 2. deselect the node
185-
selected.classed("selected", false);
186-
selected.style("stroke", "none");
187-
selected.style("stroke-width", 0);
188-
189-
}
190-
else if (event.ctrlKey) {
191-
// we will do a multi-select
192-
console.log("Branch 2 - multi select");
193-
if (len < 2) {
194-
// Then Just add selected onto the end of the array, and style it
195-
//
196-
console.log("Branch 2.1 - multi select, just add one");
197-
console.log("ns.selectArray->", ns.selectArray);
198-
// 1. add the data element to the array
199-
ns.selectArray.push(d);
200-
// 2. highlight the node
201-
selected.classed("selected", true);
202-
selected.style("stroke", ns.theme.select);
203-
selected.style("stroke-width", 5);
204-
} else if (len === 2) {
205-
// First deselect the first in the list, then add the new one
206-
//
207-
console.log("Branch 2.2 - multi select, take one off");
208-
console.log("ns.selectArray->", ns.selectArray);
209-
// 1. We need to get and remove the first object in the select array
210-
let deselect = ns.selectArray.shift();
211-
// 2. Get the DOM object that has to be deselected based on the id
212-
const deselected = d3.select("#" + deselect.id);
213-
console.log("multi deselect->", deselect);
214-
console.log("multi deselected->", deselected);
215-
// 3. Use the deselected object ref to remove the styling
216-
deselected.classed("selected", false);
217-
deselected.style("stroke", "none");
218-
deselected.style("stroke-width", 0);
219-
// 4. Add the new data element to the select array
220-
ns.selectArray.push(d);
221-
// 5. Highlight the selected node
222-
selected.classed("selected", true);
223-
selected.style("stroke", ns.theme.select);
224-
selected.style("stroke-width", 5);
225-
} else {
226-
console.log("ERORR: multi-select array is broken, too many items", );
227-
ns.selectArray.length = 0;
228-
}
229-
273+
const isAlreadySelected = ns.selection.has(id);
274+
275+
console.log("isAlreadySelected->", isAlreadySelected);
276+
277+
//unselect me if already selected
278+
if (isAlreadySelected) {
279+
ns.selection.remove(id, data);
280+
selected.classed("select-source", false);
281+
selected.classed("select-target", false);
282+
selected.classed("select-other", false);
230283
} else {
231-
// we will do a single select
232-
console.log("Branch 3 - single select");
233-
if (len === 0) {
234-
// Then Just add selected onto the end of the array, and style it
235-
//
236-
console.log("Branch 3.1 - Just add the new one");
237-
console.log("ns.selectArray->", ns.selectArray);
238-
// 1. add the data element to the array
239-
ns.selectArray.push(d);
240-
// 2. highlight the node
241-
selected.classed("selected", true);
242-
selected.style("stroke", ns.theme.select);
243-
selected.style("stroke-width", 5);
244-
} else {
245-
// Deselect all in the list, then add the new one
246-
//
247-
console.log("Branch 3.2 - Deselect everything in the list, empty it, and then just add the new one");
248-
console.log("ns.selectArray->", ns.selectArray);
249-
// 1. Deselect each object in the array
250-
ns.selectArray.forEach((item, index) => {
251-
// 2. Get the DOM object that has to be deselected based on the id
252-
const deselected = d3.select("#" + item.id);
253-
console.log("single deselect->", item);
254-
console.log("single deselected->", deselected);
255-
// 3. Use the deselected object ref to remove the styling
256-
deselected.classed("selected", false);
257-
deselected.style("stroke", "none");
258-
deselected.style("stroke-width", 0);
259-
260-
});
261-
// 2. Make the List Empty
262-
ns.selectArray.length = 0;
263-
// 3. add the new data element to the array
264-
ns.selectArray.push(d);
265-
// 5. Highlight the newly selected node
266-
selected.classed("selected", true);
267-
selected.style("stroke", ns.theme.select);
268-
selected.style("stroke-width", 5);
284+
//add me to selection and get back anything that was removed
285+
const removedData = ns.selection.add(id, data);
286+
// if we have removed data, then we need to deselect it
287+
const removedId = removedData ? removedData.id : null;
288+
if (removedId !== null) {
289+
const removedElement = removedData.element;
290+
removedElement.classed("select-source", false);
291+
removedElement.classed("select-target", false);
292+
removedElement.classed("select-other", false);
269293
}
270294
}
295+
296+
//highlight the first item
297+
const firstItem = ns.selection.getFirst();
298+
console.log("firstItem->", firstItem);
299+
if (firstItem) {
300+
const firstElement = firstItem.element;
301+
firstElement.classed("select-source", true);
302+
firstElement.classed("select-target", false);
303+
firstElement.classed("select-other", false);
304+
}
305+
306+
//highlight the last item
307+
const lastItem = ns.selection.getLast();
308+
console.log("lastItem->", lastItem);
309+
if (lastItem) {
310+
const lastElement = lastItem.element;
311+
lastElement.classed("select-source", false);
312+
lastElement.classed("select-target", true);
313+
lastElement.classed("select-other", false);
314+
}
315+
271316
console.groupEnd();
272317
}
273318

0 commit comments

Comments
 (0)