With GOJS tree view, I need to provide the search functionality. Whenever user types something for search, the search text appearing in various nodes needs to be highlighted.
From fourm & API , understands that with GOJS it is not possible to support html text for TextBlock.
I guess, expected functionality can be achieved by -
making binding of array of text with help of converter ( The converter splits the text in multiple values depending on search)
I would like to know to which template/object that can be binded.
Can you provide me template/object of GOJS where array of text can be binded and it gets displayed in single row.
I wonder if it might be possible to measure the start and end points of the searched-for text in the rendered TextBlock. Then you can draw your own highlighting – perhaps a colored rectangle behind that text, or perhaps a colored line underneath that text. That would avoid having to break up the TextBlock into multiple TextBlocks.
My original tree view was implemented using HTML.
With that when I search for “o” then “Northwoods Software” shows all “o” highlighted.
As I type “oft” then only the alphabets from “Software” gets highlighted.
Customer expects similar behaviour with Tree View implemented using goJS.
OK, what I am giving here works in a limited number of circumstances.
First you’ll need to wrap the TextBlock with a “Position” Panel named “TEXTPANEL”.
myDiagram.nodeTemplate =
$(go.Node, . . .,
// wrap each TextBlock with this Panel, which may hold some Shapes acting as highlight blocks
$(go.Panel, "Position",
{ name: "TEXTPANEL", . . . },
$(go.TextBlock,
{ name: "TEXTBLOCK", . . . })
)
);
Then you can call highlightString:
function highlightString(str) {
var oldskips = myDiagram.skipsUndoManager;
myDiagram.skipsUndoManager = true;
myDiagram.startTransaction();
myDiagram.nodes.each(function(n) {
var tb = n.findObject("TEXTBLOCK");
var pan = n.findObject("TEXTPANEL");
if (tb === null || pan === null) return;
// clear out any old highlight blocks
while (pan.elements.count > 1) {
if (pan.elt(0).name !== "TEXTBLOCK") {
pan.removeAt(0);
}
}
//??? doesn't handle wrapping in the middle of a search string
var strwidth = getStringWidth(str, tb.font);
var fontheight = getFontHeight(tb.font);
var metrics = tb.metrics;
var strArray = metrics.arrText;
var y = tb.spacingAbove;
for (var li = 0; li < strArray.length; li++) {
var line = strArray[li];
if (line.indexOf(str) >= 0) {
var split = line.split(str);
var x = 0;
for (var si = 0; si < split.length-1; si++) {
x += getStringWidth(split[si], tb.font);
var lite = new go.Shape();
lite.strokeWidth = 0;
lite.fill = "yellow";
lite.width = strwidth;
lite.height = fontheight;
//??? doesn't work for "start" and "end" in RTL languages
var indent = 0;
if (tb.textAlign === "center") indent = (metrics.maxLineWidth - metrics.arrSize[li]) / 2;
else if (tb.textAlign === "right" || tb.textAlign === "end") indent = (metrics.maxLineWidth - metrics.arrSize[li]);
lite.position = new go.Point(x + indent, y);
pan.insertAt(0, lite);
x += strwidth;
}
}
y += fontheight + tb.spacingBelow + tb.spacingAbove;
}
});
myDiagram.commitTransaction("highlightString");
myDiagram.skipsUndoManager = oldskips;
}
var SharedCtx = document.createElement("canvas").getContext("2d");
var SharedCtxFont = null;
function getStringWidth(str, font) {
if (str === "") return 0;
if (SharedCtxFont !== font) {
SharedCtx.font = font;
SharedCtxFont = font;
}
return SharedCtx.measureText(str).width;
};
function getFontHeight(font) {
var metrics = SharedCtx.measureText('M');
return metrics.width * 1.3; //??? SUPER ARBITRARY 30%
}
Note that this code does not handle line wrapping within the search string. If you want that, you can adapt this code.
Also I didn’t bother handling RTL languages. Or multiple TextBlocks within a Node. Or any TextBlock within a Link or a plain Part.
Another restriction: you have to call highlightString no earlier than in an “InitialLayoutCompleted” DiagramEvent listener.