function updateChart(filename, chartDs, days){ // called by contentbuffer if(chartDs != "undefined"){ setTimeout("setChartData('" + chartDs + "','" + days + "')", 10); } setChartImg(filename); } function setChartImg(filename){ document.getElementById("insidersChartImg").src = filename; document.getElementById("insidersChartImg").style.visibility = "visible"; document.getElementById("image").removeChild(document.getElementById("divLoading")); if(pid != 0){ showScores(); } } function showScores() { var pos = getAbsolutePos(document.getElementById("image")); document.getElementById("scores").style.top = pos.y - 2 + "px"; document.getElementById("scores").style.left = pos.x + 6 + "px"; document.getElementById("scores").innerHTML = insiders[0].name + " Insider Activity -BUY Score: " + buyScore + " SELL Score: " + sellScore; } function setChartData(chartDs, days){ chartData = {}; if(chartDs) { if(chartDs.length > 3) { chartDs = chartDs.split("&"); try { chartData = { x0: arrayDecodeUnpack(chartDs[0]), y0: arrayDecodeUnpack(chartDs[1]), date: arrayDecodeUnpack(chartDs[2]), value: arrayDecodeUnpack(chartDs[3]), dateNice: chartDs[4].split(",") } } catch(e){ /*dbg("error chartData","","red");*/ } } } optimizeChartData(); drawIcons(); if(pid != "0"){ setInsiderHistoryText(days.toString()); } } function optimizeChartData() { var optSize = Math.floor(document.getElementById("insidersChartImg").width / 9); if(!chartData.date){ return; } if(chartData.date.length <= optSize){ return; } var x, y; var interval = chartData.date.length / optSize; var temp = {x0: new Array(), y0: new Array(), date: new Array(), value: new Array(), dateNice: new Array()}; for(x = 0; x < chartData.date.length-1; x += interval) { y = Math.round(x); temp.x0.push(chartData.x0[y]); temp.y0.push(chartData.y0[y]); temp.date.push(chartData.date[y]); temp.value.push(chartData.value[y]); temp.dateNice.push(chartData.dateNice[y]); } chartData = temp; } function getClosestDateIdx (date) { // quick search; assumes a sorted list // need error handling for dates outside of range if (typeof(chartData) == "undefined" || !chartData.date){ return false; } var left = 0; var right = chartData.date.length - 1; var i = Math.round((right - left) / 2); if (date < chartData.date[left] || date > chartData.date[right]) { return false; } while (chartData.date[i] != date && left != right) { // return first data point greater than date if (chartData.date[i] > date && chartData.date[i-1] < date) { break; } if (chartData.date[i] < date && chartData.date[i+1] > date) { i++; break; } if (chartData.date[i] > date) { right = i; i = Math.floor((right - left) / 2) + left; } else if (chartData.date[i] < date) { left = i; i = Math.ceil((right - left) / 2) + left; } } //dbg(i, chartData.date[i] + "," + left + "/" + right, "red") return (left == right && chartData.date[i] != date)?false:i; } function hideIcons() { for (var x=0; x < insiders.length; x++){ i = insiders[x]; if (i.img){ i.img.style.visibility = "hidden"; } } } function setLegendText(days){ var idx = (days == 1825)?2:(days == 1095)?1:0; document.getElementById("legend").innerHTML = legendText[idx]; } function getPlural(num){ return (num == 1)?"":"s"; } function getEvents(days, eventDesc){ // used for part of insider history text calculations var txt = ""; var data = []; var descEng = (eventDesc == "Purchase") ? "Purchase" : "Sale"; for (var i,x=0; x < insiders.length; x++){ if (insiders[x].desc == eventDesc){ data.push(insiders[x]); } } txt += data.length + " " + descEng + getPlural(data.length) + " in the last "; txt += ((days == "365")?"12 Months":(days == "1095")?"3 Years":"5 Years"); return {txt: txt, data: data}; } function getAvg(data, months) { var avgData = { weighted: [], shares: [], high: 0, low: 0, avg: 0 } var totShares = 0; for (var start, x=0; x < data.length; x++){ start = data[x].dataCurr end = (months == 3) ? data[x].data3Mo : data[x].data6Mo; if (!end){ continue; } if (end.price > start.price){ avgData.high += 1; } else if (end.price < start.price){ avgData.low += 1; } end.pctChg = getPctChange(start.price, end.price); data[x].dataNow.pctChg = getPctChange(start.price, data[x].dataNow.price); avgData.weighted.push(end.pctChg * start.shares); totShares += parseInt(start.shares); /* dbg("calculating for " + months + " months", "purple") dbg("   start", start.price, "purple"); dbg("   end", end.price, "purple"); dbg("   % chg", end.pctChg, "purple"); dbg("   shares", start.shares, "purple"); dbg("   weighted shares", avgData.weighted[avgData.weighted.length - 1], "purple"); */ } if (avgData.weighted.length > 0){ // sum up the weighted shares var totWeighted = 0; for (var x=0; x < avgData.weighted.length; x++){ totWeighted += avgData.weighted[x]; } avgData.avg = Math.round((totWeighted / totShares) * 10) / 10; /* dbg("TOTALS","","black") dbg("totWeighted", totWeighted, "black") dbg("totShares", totShares, "black") dbg("avg", (totWeighted / totShares), "black") */ } return avgData; } function getPctChange(a,b){ return parseFloat(((b < a)?"-":"") + ((Math.abs(b - a) / Math.abs(a)) * 1000) / 10); } function setInsiderHistoryText(days){ if (typeof insiderText == "undefined"){ insiderText = []; } if (!insiderText[days]){ var buys = getEvents(days, "Purchase"); var sells = getEvents(days, "Sale"); var avgBuy3Mo = getAvg(buys.data, 3); var avgBuy6Mo = getAvg(buys.data, 6); var avgSell3Mo = getAvg(sells.data, 3); var avgSell6Mo = getAvg(sells.data, 6); insiderText[days] = { txtNumBuys: buys.txt, txtNumSells: sells.txt, txtAvgBuy3Mo: (avgBuy3Mo.avg != 0) ? avgBuy3Mo.avg + "%" : "--", txtAvgBuy6Mo: (avgBuy6Mo.avg != 0) ? avgBuy6Mo.avg + "%" : "--", txtAvgSell3Mo: (avgSell3Mo.avg != 0) ? avgSell3Mo.avg + "%" : "--", txtAvgSell6Mo: (avgSell6Mo.avg != 0) ? avgSell6Mo.avg + "%" : "--", txtNumBuyHigh3Mo: (avgBuy3Mo.high != 0) ? avgBuy3Mo.high + " higher" : "--", txtNumBuyHigh6Mo: (avgBuy6Mo.high != 0) ? avgBuy6Mo.high + " higher" : "--", txtNumBuyLow3Mo: (avgBuy3Mo.low != 0) ? avgBuy3Mo.low + " lower" : "--", txtNumBuyLow6Mo: (avgBuy6Mo.low != 0) ? avgBuy6Mo.low + " lower" : "--", txtNumSellHigh3Mo: (avgSell3Mo.high != 0) ? avgSell3Mo.high + " higher" : "--", txtNumSellHigh6Mo: (avgSell6Mo.high != 0) ? avgSell6Mo.high + " higher" : "--", txtNumSellLow3Mo: (avgSell3Mo.low != 0) ? avgSell3Mo.low + " lower" : "--", txtNumSellLow6Mo: (avgSell6Mo.low != 0) ? avgSell6Mo.low + " lower" : "--" } } var data = insiderText[days.toString()]; for (var x in data){ document.getElementById(x).innerHTML = data[x]; } } var iconTypes = [ {img: "iconBuy", regex: /purchase/i, offY: -7}, {img: "iconSell", regex: /^sale/i, offY: 7}, {img: "iconEx", regex: /exercise/i, offY: 7}, {img: "iconPlan", regex: /plan/i, offY: -7}, {img: "iconGift", regex: /gift/i, offY: 0}, {img: "iconAward", regex: /award/i, offY: 0} ]; function qsort(ins) { var l = new Array(); var e = new Array(); var g = new Array(); if(ins.length <= 1){ return ins; } else { var pivot = ins[Math.floor(ins.length/2)].shares; for(var i = 0; i < ins.length; i++) { if(ins[i].shares < pivot){ l.push(ins[i]); } else if(ins[i].shares == pivot){ e.push(ins[i]); } else{ g.push(ins[i]); } } return qsort(l).concat(e).concat(qsort(g)); } } function drawIcons(filter) { var start = new Date().getTime(); var origin = getAbsolutePos(document.getElementById("insidersChartImg")); filter = (filter)?filter:(typeof(currentTab) != "undefined")?currentTab:"tab0"; var count = 0; var usedDates = new Array(); var worstCase = 1000;//chartData.date.length * 3; var iTypes = new Array(); iTypes["Stock Gift"] = 10; iTypes["Award of Stock Options"] = 10; iTypes["Planned Sale"] = 3; iTypes["Purchase"] = 3; iTypes["Sale"] = 17; iTypes["Exercise of Stock Options"] = 17; //sort insiders based on shares moved insiders = qsort(insiders).reverse(); for(var i, closest, x=0; x < insiders.length && count < worstCase; x++) { i = insiders[x]; closest = getClosestDateIdx(i.date); if (closest) { //if there is already a value for the date try another if(usedDates[chartData.date[closest]*iTypes[i.desc]]){ continue; } else { usedDates[chartData.date[closest]*iTypes[i.desc]] = true; count++; } if (!i.img){ // properties that only get set once. var screen = document.getElementById("screen"); if (screen){ i.img = screen.appendChild(document.createElement("IMG")) } else { i.img = document.body.appendChild(document.createElement("IMG")) } i.img.style.width = "9px"; i.img.style.height = "8px"; i.img.style.position = "absolute"; for (var iT, y=0; y < iconTypes.length; y++){ iT = iconTypes[y]; if (iT.regex.test(i.desc)){ i.img.src = "https://thomson.cache.wallst.com/img/" + iT.img + ".gif"; i.img.style.visibility = (filter == "tab0" || filter == "tab" + (y+1))?"visible":"hidden"; i.offY = iT.offY; } else { //dbg("couldn't match " + iT.regex,i.desc,"red") } } i.img.id = "insider" + x; i.img.onmouseover = showDetail; i.img.onmouseout = showOrigDetail; if (pid != "0"){ // future performance date i.dataCurr = { shares: parseInt(insiders[x].shares), sharesNice: insiders[x].num, price: chartData.value[closest], dateNice: chartData.dateNice[closest] }; var idx3Mo = getClosestDateIdx(parseInt(i.date) + 91) var idx6Mo = getClosestDateIdx(parseInt(i.date) + 182); if (idx3Mo){ i.data3Mo = { price: chartData.value[idx3Mo], dateNice: chartData.dateNice[idx3Mo] }; } if (idx6Mo){ i.data6Mo = { price: chartData.value[idx6Mo], dateNice: chartData.dateNice[idx6Mo] }; } i.dataNow = { price: chartData.value[chartData.date.length - 1], dateNice: chartData.dateNice[chartData.date.length - 1] } } } // properties that get set every time. for (var y=0; y < iconTypes.length; y++){ if (iconTypes[y].regex.test(i.desc)){ i.img.style.visibility = (filter == "tab0" || filter == "tab" + (y+1))?"visible":"hidden"; } } with (i.img) { style.left = origin.x + chartData.x0[closest] - 4.5 + "px"; try { style.top = ((i.offY)?i.offY:0) + origin.y + chartData.y0[closest] - 4 + "px"} catch(e){} } } else { //dbg("could not find closest index", i.date + "(" + formatDate(msToJsDate(i.date), "MMM dd, yyyy") + ")", "red"); } } } function initChart(){ contentBuffer = new ContentBuffer(); // assign event handlers to buttons for (var x=0; x < 3; x++){ var btnObj = document.getElementById("btn" + x); //btnObj.onclick = loadChart; addEvent(btnObj, "click", getTableData); addEvent(btnObj, "click", loadChart); } loadChart(); } function showDetail(event) { var leg = document.getElementById("legend"); leg.style.paddingTop = "7px"; if (typeof origDetail == "undefined"){ origDetail = leg.innerHTML; } if (typeof origRowHigh == "undefined"){ origRowHigh = []; } var e = event || window.event || false; var srcElement = false; if (e){ srcElement = getSrcElement(e); } var idx = parseInt(srcElement.id.replace("insider","")); var i = insiders[idx]; if (pid == "0" || !/^sale|purchase/i.test(i.desc)){ var html = ""; html += "" + i.name + "
" html += " Largest " + i.desc + "
" html += formatDate(msToJsDate(i.date), "MMM dd, yyyy") + "
" html += commatize(i.shares) + " shares
" } else { var engDesc = (/^sale/i.test(i.desc))?"Sold":"Purchased"; var pct; var html = '
' + i.dataCurr.sharesNice + ' shares ' + engDesc + ' on ' + i.dataCurr.dateNice + '
'; if (i.data3Mo){ html += '
3 Mo. Performance:
'+i.dataCurr.dateNice+' - '+i.data3Mo.dateNice+'
price increase':'down">decrease')+' of ' + Math.abs(Math.round(i.data3Mo.pctChg * 10) / 10) + '%
'; } if (i.data6Mo){ html += '
6 Mo. Performance:
'+i.dataCurr.dateNice+' - '+i.data6Mo.dateNice+'
price increase':'down">decrease')+' of ' + Math.abs(Math.round(i.data6Mo.pctChg * 10) / 10) + '%
'; } if (i.dataNow) { pct = getPctChange(i.dataCurr.price, i.dataNow.price); html += '
Performance to Date:
'+i.dataCurr.dateNice+' - '+i.dataNow.dateNice+'
price increase':'down">decrease')+' of ' + Math.abs(Math.round(pct * 10) / 10) + '%
'; } } html += tableView; leg.innerHTML = html; highlightTableRow(insiders[idx].date, insiders[idx].desc); } function showOrigDetail(event) { if (origDetail){ document.getElementById("legend").innerHTML = origDetail; } if (origRows){ highlightTableRow(); } } function highlightTableRow(date, type) { var rows = document.getElementsByTagName("TR"); if (date){ // on origRows = []; for (var msd, type, len, cols, x=0; x < rows.length; x++){ msd = rows[x].getAttribute("msdate"); tranType = rows[x].getAttribute("tranType"); //if (msd && tranType && msd == date && type == tranType){ if (msd && msd == date){ len = origRows.length; origRows.push([]) cols = rows[x].getElementsByTagName("td"); for (var y=0; y < cols.length; y++){ origRows[len].push(cols[y].className); cols[y].className = "bgHighlight col" + y; } } } } else { // off for (var cn, oCnt = 0, len, cols, x=0; x < rows.length; x++){ cols = rows[x].getElementsByTagName("td"); if (cols.length > 0){ cn = cols[0].className; if (cn.search("bgHighlight") > -1){ for (var y=0; y < cols.length; y++){ cols[y].className = origRows[oCnt][y]; } oCnt++ } } } origRows = []; } } function loadChart(event) { var e = event || window.event || false; var srcElement = false; hideIcons(); var img = document.getElementById("insidersChartImg"); var xy = getAbsolutePos(img); var div = document.getElementById("divLoading"); if(div){ document.getElementById("image").removeChild(div); } div = document.createElement("div"); img.src = "https://thomson.cache.wallst.com/img/x.gif"; div.id = "divLoading"; div.innerHTML = "Loading ..."; div.style.border = "none"; div.style.textAlign = "center"; div.style.background = "none"; div.style.position = "absolute"; div.style.left = xy.x + "px"; div.style.top = xy.y + "px"; div.style.width = img.width + "px"; div.style.height = img.height + "px"; div.style.lineHeight = div.style.height; div.style.zIndex = 99; div.style.visibility = "visible"; img.style.visibility = "hidden"; document.getElementById("image").appendChild(div); if (e && getSrcElement(e) && getSrcElement(e).id.match("btn")){ srcElement = getSrcElement(e); } else { if(document.getElementById("btn0").className == "on"){ srcElement = document.getElementById("btn0"); } else if(document.getElementById("btn1").className == "on"){ srcElement = document.getElementById("btn1"); } else if(document.getElementById("btn2").className == "on"){ srcElement = document.getElementById("btn2"); } } var days = ((srcElement)?srcElement.getAttribute("days"):365); if(e) { //Get the tab var evtType = "all"; var clkEle = getSrcElement(e); if(clkEle != undefined) { if(clkEle.getAttribute("evtType")) { //Tab clicked evtType = clkEle.getAttribute("evtType"); } else { //Date range click - days have already been gotten - get selected tab evtType = document.getElementById(document.getElementById("tabNavSelected").getAttribute("selectedtab")).getAttribute("evtType"); } } } else { var evtType = "all"; } setLegendText(days); contentBuffer.abortRequests(); contentBuffer.load({ url: "resources/asp/getBufferedInsidersChartData.asp", method: "post", contentType: "text/javascript", postdata: { bridgeSymbol: symbolBridge, symbolWSODIssue: symbolWSODIssue, Years: days/365, Event: evtType, pid: pid}, debug: true }); for (var x=0; x < 3; x++) { var btnObj = document.getElementById("btn" + x); btnObj.className = (btnObj.getAttribute("days") == days)?"on":""; } } function getChart(days) { contentBuffer.load({ url: "resources/asp/getBufferedChart.asp", method: "post", contentType: "text/javascript", postdata: { params: "symbol=" + symbolBridge + "&symbolWSODIssue=" + symbolWSODIssue + "&timeFrame=" + days + "&width=" + width, cht: "insiderActivity", callback: "updateChart", returnVars: "File.Name,ChartDS,timeFrame" }, debug: true }); } function getTableData(event){ var e = event || window.event || false; var srcElement = false; if(e && getSrcElement(e) && getSrcElement(e).id.match("btn")) { srcElement = getSrcElement(e); } //Update tableprefs.years tableprefs.Years = ((srcElement) ? parseInt(srcElement.getAttribute("days")/365) : 1); //tableBuffer.abortRequests(); tableBuffer.load({ url: "resources/asp/getBufferedInsiders.asp", method: "post", contentType: "text/javascript", postdata: { securityID: securityID, pid: tableprefs.pid, Event: tableprefs.Event, Years: tableprefs.Years, SortBy: sortCols[tableprefs.SortBy], SortDirection: tableprefs.SortDirection, FirstRow: 1, callback: "updateTable" }, debug: true }); } function selectTabNavContent(id){ currentTab = (typeof currentTab == "undefined")?"tab0":id; if (typeof selectEvent != "undefined"){ //setTimeout('selectEvent("'+id+'")',10); selectEvent(id); } } function initTabButtons() { // assign button handlers var el; for (var x=0; x < 7; x++) { el = document.getElementById("tab" + x); addEvent(el, "click", selectTabNav); addEvent(el, "click", loadChart); } selectTabNav(false, document.getElementById("tab0")); } function commatize(n) { n += ""; var ns = "", rem = ""; var dp = n.indexOf('.'); var sp = (dp >= 0) ? dp : n.length; ns = n.substring(sp, n.length); if(n.indexOf("+") >= 0) { var plus = true; n = n.substring(n.indexOf("+")+1, sp); } else if(n.indexOf("-") >= 0) { var minus = true; n = n.substring(n.indexOf("-")+1, sp); } else{ n = n.substring(0, sp); } rem = n; for(var i = n.length - 3; i > 0; i -= 3) { ns = ',' + n.substring(i, i+3) + ns; rem = n.substring(0, i); } if(plus){ return "+" + rem + ns; } else if(minus){ return "-" + rem + ns; } else{ return rem + ns; } } function msToJsDate(msdate) { var jscriptDateObj = new Date(((msdate - 25569) * 86400000)) // get the tzoffset, as the jscript date comes in offset from the UTC msdate var timezoneOffset = jscriptDateObj.getTimezoneOffset() // recalculate the jscriptDate, with the tzoffset factor taken into account; this gives us a jscript date that matches the msdate jscriptDateObj = new Date(((msdate - 25569 + (timezoneOffset / (60 * 24))) * 86400000)) return jscriptDateObj; } function jsToMsDate(jsdate) { var ms = Date.UTC(jsdate.getUTCFullYear(), jsdate.getUTCMonth(), jsdate.getUTCDate(), jsdate.getUTCHours(), jsdate.getUTCMinutes(), jsdate.getUTCSeconds(), jsdate.getUTCMilliseconds()); var off = jsdate.getTimezoneOffset(); return ((ms - (off*60*1000)) / 86400000) + 25569; } function LZ(x) { return (x < 0 || x > 9 ? "" : "0" ) + x } function formatDate(date,format) { var DAY_NAMES = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); var MONTH_NAMES = new Array('January','February','March','April','May','June','July','August','September','October','November','December'); format = format + ""; var result = ""; var i_format = 0; var c = ""; var token = ""; var y = date.getYear() + ""; var M = date.getMonth() + 1; var d = date.getDate(); var E = date.getDay(); var H = date.getHours(); var m = date.getMinutes(); var s = date.getSeconds(); var yyyy, yy, MMM, MM, dd, hh, h, mm, ss, ampm, HH, H, KK, K, kk, k; var value = new Object(); if(y.length < 4){ y = "" + (y-0+1900); } value["y"] = "" + y; value["yyyy"] = y; value["yy"] = y.substring(2, 4); value["M"] = M; value["MM"] = LZ(M); value["MMM"] = MONTH_NAMES[M - 1]; value["d"] = d; value["dd"] = LZ(d); value["E"] = DAY_NAMES[E +7 ]; value["EE"] = DAY_NAMES[E]; value["H"] = H; value["HH"] = LZ(H); if(H == 0){ value["h"] = 12; } else if(H > 12){ value["h"] = H - 12; } else{ value["h"] = H; } value["hh"] = LZ(value["h"]); if(H > 11){ value["K"] = H - 12; } else{value["K"] = H; } value["k"] = H + 1; value["KK"] = LZ(value["K"]); value["kk"] = LZ(value["k"]); if(H > 11){ value["a"] = "pm"; } else{ value["a"] = "am"; } value["m"] = m; value["mm"] = LZ(m); value["s"] = s; value["ss"] = LZ(s); while(i_format < format.length) { c = format.charAt(i_format); token = ""; while((format.charAt(i_format)==c) &&(i_format < format.length)) { token += format.charAt(i_format++); } if(value[token] != null){ result = result + value[token]; } else{ result=result + token; } } return result; } addEvent(window, "load", initTabButtons); addEvent(window, "load", initChart);