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 = '