Index: openacs-4/packages/xotcl-request-monitor/xotcl-request-monitor.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/xotcl-request-monitor.info,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/xotcl-request-monitor.info 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,53 @@ + + + + + XOTcl Request Monitor + XOTcl Request Monitor + f + t + request-monitor + + + Gustaf Neumann + Request Monitor with user tracking functionality + 2005-12-11 + This package provides a Request Monitor for OACS applications. +It computes performance summary information such as requests/views per +seconds, average response time, number of users connected, +lists currently active threads, etc. Furthermore +it can block overactive users (e.g. automated web-bots mirroring the site, users repeating running queries, etc.). It provides as well some user tracking +(such as whos-online) with activity measures, it blocks +repeated requests (impatient reloads), tracks switching of IP-adresses from users and provides request tracking per user for the monitored time window. It contains +as well overall url statistics with performance measures. +Updated for cirumventing handler calls openacs 5.2 for /resources/*. 0.28 provides calles for listing active communities and users active in these communities. 0.30 provides a nice graphical chats (many thanks to Nima) and +a new interface to the background thread. In addition, +ns_returnfile_background is included + 0 + + + + + + + + + + + + + + + Index: openacs-4/packages/xotcl-request-monitor/tcl/background-delivery-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/tcl/Attic/background-delivery-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/tcl/background-delivery-procs.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,59 @@ +ad_library { + + Routines for background delivery of files + + @author Gustaf Neumann (neumann@wu-wien.ac.at) + @creation-date 19 Nov 2005 + @cvs-id $Id: background-delivery-procs.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} + +::xotcl::THREAD create bgdelivery { + set ::delivery_count 0 + + proc deliver {ch filename context} { + set fd [open $filename] + fconfigure $fd -translation binary + fconfigure $ch -translation binary + #ns_log notice "--- start of delivery of $filename (running:[array size ::running])" + fcopy $fd $ch -command [list end-delivery $filename $fd $ch] + set ::running($ch,$filename) $context + incr ::delivery_count + } + + proc end-delivery {filename fd ch bytes args} { + #ns_log notice "--- end of delivery of $filename, $bytes bytes written $args" + if {[catch {close $ch} e]} {ns_log notice "delivery, closing channel for $filename, error: $e"} + if {[catch {close $fd} e]} {ns_log notice "delivery, closing file $filename, error: $e"} + unset ::running($ch,$filename) + } +} -persistent 1 + +bgdelivery ad_forward running { + Interface to the background delivery thread to query the currently running deliveries. + @return list of key value pairs of all currently running background processes +} %self do array get running + + +bgdelivery ad_forward nr_running { + Interface to the background delivery thread to query the number of currently running deliveries. + @return number of currently running background deliveries +} %self do array size running + + +ad_proc -public ad_returnfile_background {statuscode mime_type filename} { + Deliver the given file to the requestor in the background. This proc uses the + background delivery thread to send the file in an event-driven manner without + blocking a request thread. This is especially important when large files are + requested over slow (e.g. dial-ip) connections. +} { + #ns_log notice "statuscode = $statuscode, filename=$filename" + set size [file size $filename] + if {[ns_headers xxx $statuscode $mime_type $size]} { + set ch [ns_conn channel] + thread::transfer [bgdelivery get_tid] $ch + throttle get_context + bgdelivery do -async deliver $ch $filename \ + [list [throttle set requestor],[throttle set url] [ns_conn start]] + ns_conn contentsentlength $size; #maybe overly optimistic + } +} Index: openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-init.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-init.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,26 @@ + +# we register the following filters only during startup, since +# existing connection threads are not aware of the throttle object. +if {[ns_server connections]==0} { + # + # Register the filter progs for url statistics. + # The methods to be called have the name of the filter type. + # + ns_register_filter trace GET * throttle + ns_register_filter trace POST * throttle + + #ns_register_filter postauth GET * throttle + #ns_register_filter postauth POST * throttle + ad_register_filter -priority 1000 postauth GET * throttle + ad_register_filter -priority 1000 postauth POST * throttle +} + +# check if we are running under oacs; if not, provide +# minimal compatibility code +if {[info commands ad_conn] eq ""} { + # otherwise provide alias for ad_conn and dummy for ad_get_user_id + interp alias {} ad_conn {} ns_conn + ### this is probably not sufficient to do something useful... +} + + Index: openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-procs.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,837 @@ +############################################################################# +::xotcl::THREAD create throttle { + + Class create ThrottleStat -parameter { type requestor timestamp ip_adress url } + + Class create Throttle -parameter { + {timeWindow 10} + {timeoutMs 2000} + {startThrottle 7} + {toMuch 10} + {alerts 0} {throttles 0} {rejects 0} {repeats 0} + } + + Throttle instproc init {} { + my set off 0 + Object create [self]::stats + Object create [self]::users + next + } + + Throttle instproc add_statistics { type requestor ip_adress url query } { + set furl [expr {$query != "" ? "$url?$query" : $url}] + my incr ${type}s + #my log "++++ add_statistics -type $type -user_id $requestor " + set entry [ThrottleStat new -childof [self]::stats \ + -type $type -requestor $requestor \ + -timestamp [clock seconds] \ + -ip_adress $ip_adress -url $furl] + } + + Throttle instproc url_statistics {{-flush 0}} { + set data [[self]::stats info children] + if { [llength $data] == 0} { + return $data + } elseif {$flush} { + foreach c $data {$c destroy} + return "" + } else { + foreach stat $data { + lappend output [list [$stat type] [$stat requestor] \ + [$stat timestamp] [$stat ip_adress] [$stat url]] + } + return $output + } + } + + Throttle instproc call_statistics {} { + set l [list] + foreach t {seconds minutes hours} { + lappend l [list $t [$t set last] [$t set trend] [$t set stats]] + } + return $l + } + + Throttle instproc register_access {requestKey pa url community_id} { + set obj [Users current_object] + $obj addKey $requestKey $pa $url $community_id + Users expSmooth [$obj point_in_time] $requestKey + } + + + + Throttle instproc running {} { + my array get running_url + } + + Throttle instproc throttle_check {requestKey pa url conn_time content_type community_id} { + my instvar off + seconds ++ + + set var running_url($requestKey,$url) + # check first, whether the same user has already the same request + # issued; if yes, block this request. Caveat: some html-pages + # use the same image in many places, so we can't block it. This + # will make the sttistics for images look better than they are. + set is_image_request [string match image/* $content_type] + if {[my exists $var] && !$is_image_request && !$off} { + my log "### already $var" + return [list 0 0 1] + } else { + my set $var $conn_time + #my log "### new $var" + } + my register_access $requestKey $pa $url $community_id + + # ... the number of 14 is arbitrary. one of our single real request + # might have up to 14 subrequests (through iframes).... + if {$off || $is_image_request || [my array size running_url] < 14} { + + # less than forteen running requests, let people do what they want; + # don't throttle/block embedded images..... + return [list 0 0 0] + + } else { + + # Check, whether the last request from a user was within + # the minimum time interval. We are not keeping a full table + # of all request keys, but use an timeout triggered mechanism + # to keep only the active request keys in an associative array + + my incr alerts + if {[my exists active($requestKey)]} { + # if more than one request for this key is already active, + # return blocking time + foreach {to cnt} [my set active($requestKey)] break + set retMs [expr {$cnt>[my startThrottle] ? 500 : 0}] + # cancel the timeout + after cancel $to + } else { + set retMs 0 + set cnt 0 + } + incr cnt + # establish a new timeout + set to [after [my timeoutMs] [list [self] cancel $requestKey]] + my set active($requestKey) [list $to $cnt] + if {$cnt <= [my toMuch]} { + set cnt 0 + } + return [list $cnt $retMs 0] + } + } + + Throttle instproc statistics {} { + return " + + + + +
Number of alerts:[my alerts]
Number of throttles:[my throttles]
Number of rejects:[my rejects]
Number of repeats:[my repeats]
\n" + } + + Throttle instproc cancel {requestKey} { + # cancel a timeout and clean up active request table for this key + if {[my exists active($requestKey)]} { + after cancel [lindex [my set active($requestKey)] 0] + my unset active($requestKey) + #my log "+++ Cancel $requestKey block" + } else { + my log "+++ Cancel for $requestKey failed !!!" + } + } + + Throttle instproc active { } { + # return the currently active requests (for debugging and introspection) + return [my array get active] + } + + Throttle instproc add_url_stat {url time_used key pa} { + catch {my unset running_url($key,$url)} + #my log "### unset running_url($key,$url)" + response_time_minutes add_url_stat $url $time_used $key + } + Throttle instforward report_url_stats response_time_minutes %proc + Throttle instforward flush_url_stats response_time_minutes %proc + Throttle instforward last100 response_time_minutes %proc + Throttle create throttler + + ############################ + # A simple counter class, which is able to aggregate values in some + # higher level counters (report_to) and to keep statistics in form + # of a trend and max values) + Class create Counter -parameter { + report timeoutMs + {stats ""} {last ""} {trend ""} {c 0} {logging 0} + {nr_trend_elements 48} {nr_stats_elements 5} + } + Counter instproc ++ {} { + my incr c + } + Counter instproc end {} { + if {[my exists report]} { + [my report] incr c [my c] + } + my finalize [my c] + my c 0 + } + Counter instproc log_to_file {timestamp label value} { + if {![my logging]} return + set server [ns_info server] + set f [open $::logdir/counter.log a] + puts $f "$timestamp -- $server $label $value" + close $f + } + Counter instproc finalize {n} { + after cancel [my set to] + my instvar stats trend + # + # trend keeps nr_trend_elements most recent values + # + lappend trend $n + set lt [llength $trend] + if {$lt > [my nr_trend_elements]} { + set trend [lrange $trend [expr {$lt-[my nr_trend_elements]}] end] + } + # + # stats keeps nr_stats_elements highest values with time stamp + # + set now [clock format [clock seconds]] + lappend stats [list $now $n] + set stats [lrange [lsort -real -decreasing -index 1 $stats] 0 [my nr_stats_elements]] + # + # log if necessary + # + catch {my log_to_file $now [self] $n} + # + my set to [after [my timeoutMs] [list [self] end]] + } + + Counter instproc init {} { + my set to [after [my timeoutMs] [list [self] end]] + next + } + Counter instproc destroy {} { + after cancel [my set to] + next + } + + Counter hours -timeoutMs [expr {60000*60}] -logging 1 + Counter minutes -timeoutMs 60000 -report hours -logging 1 + Counter seconds -timeoutMs 1000 -report minutes + + Class create MaxCounter -superclass Counter -instproc end {} { + my c [Users nr_active] + if {[my exists report]} { + [my report] instvar {c rc} + if {$rc < [my c]} {set rc [my c]} + } + my finalize [my c] + my c 0 + } + + MaxCounter user_count_hours -timeoutMs [expr {60000*60}] -logging 1 + MaxCounter user_count_minutes -timeoutMs 60000 -report user_count_hours -logging 1 + + + Class create AvgCounter -superclass Counter \ + -parameter {{t 0} {atleast 1}} -instproc end {} { + if {[my c]>0} { + set avg [expr {int([my t]*1.0/[my c])}] + } else { + set avg 0 + } + if {[my exists report]} { + [my report] incr c [my c] + [my report] incr t [my t] + } + my finalize $avg + my c 0 + my t 0 + } + + Class create UrlCounter -superclass AvgCounter \ + -parameter {{truncate_check 10} {max_urls 0}} \ + -set seconds [clock seconds] \ + -instproc add_url_stat {url ms requestor} { + my instvar c + my ++ + # my log "[self proc] $url /$ms/ $requestor ($c)" + my incr t $ms + + ### set up a value for the right ordering in last 100. + ### We take the difference in seconds since start, multiply by + ### 10000 (there should be no overflow); there should be less + ### than this number requests per minute. + set now [clock seconds] + set order [expr {($now-[[self class] set seconds])*10000+$c}] + my set last100([expr {$order%99}]) [list $now $order $url $ms $requestor] + + ### Add statistics in detail + if {[my exists stat($url)]} { + my incr stat($url) $ms + my incr cnt($url) + } else { + my set stat($url) $ms + my set cnt($url) 1 + } + } -instproc last100 {} { + my array get last100 + } -instproc flush_url_stats {} { + my log "flush_url_stats" + my array unset stat + my array unset cnt + } -instproc url_stats {} { + set result [list] + foreach url [my array names stat] { + lappend result [list $url [my set stat($url)] [my set cnt($url)]] + } + set result [lsort -real -decreasing -index 1 $result] + return $result + } -instproc check_truncate_stats {} { + # truncate statistics if necessary + if {[info exists ::package_id]} { + # get values from package parameters + my max_urls [parameter::get -package_id $::package_id \ + -parameter max-url-stats -default 13] + # we use the timer to check other parameters as well here + set time_window [parameter::get -package_id $::package_id \ + -parameter time-window -default 10] + if {$time_window != [throttler timeWindow]} { + throttler timeWindow $time_window + after 0 [list Users purge_access_stats] + } + } + set max [my max_urls] + if {$max>1} { + set result [my url_stats] + set l [llength $result] + for {set i $max} {$i<$l} {incr i} { + set url [lindex [lindex $result $i] 0] + my unset stat($url) + my unset cnt($url) + } + set result [lrange $result 0 [expr {$max-1}]] + return $result + } + return "" + } -instproc report_url_stats {} { + set stats [my check_truncate_stats] + if {$stats eq ""} { + set stats [my url_stats] + } + return $stats + } -instproc finalize args { + next + # each time the timer runs out, perform the cleanup + after 0 [list [self] check_truncate_stats] + } + + + UrlCounter response_time_hours -timeoutMs [expr {60000*60}] \ + -atleast 500 -logging 1 + UrlCounter response_time_minutes -timeoutMs 60000 \ + -report response_time_hours -atleast 100 \ + -logging 1 + + # + # Class for the user tracking + + Class create Users -parameter { point_in_time } -ad_doc { + This class is responsible for the user tracking and is defined only + in a separate Tcl thread named throttle. + For each minute within the specified time-window an instance + of this class exists keeping various statistics. + When a minute ends the instance dropping out of the + time window is destroyed. The procs of this class can be + used to obtain various kinds of information. + + @author Gustaf Neumann + @cvs-id $Id: throttle_mod-procs.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ + } + Users ad_proc active {-full:switch} { + Return a list of lists containing information about current + users. If the switch 'full' is used this list contains + these users who have used the server within the + monitoring time window (per default: 10 minutes). Otherwise, + just a list of requestors (user_ids or peer addresses for unauthenticated + requests) is returned. +

+ If -full is used for each requestor the last + peer address, the last timestamp, the number of hits, a list + of values for the activity calculations and the number of ip-switches + the user is returned. +

+ The activity calculations are performed on base of an exponential smoothing + algorithm which is calculated through an aggregated value, a timestamp + (in minutes) and the number of hits in the monitored time window. + @return list with detailed user info + } { + if {$full} { + set info [list] + foreach key [my array names pa] { + set entry [list $key [my set pa($key)]] + foreach var [list timestamp hits expSmooth switches] { + set k ${var}($key) + lappend entry [expr {[my exists $k] ? [my set $k] : 0}] + } + lappend info $entry + } + return $info + } else { + return [my array names pa] + } + } + Users proc unknown { obj args } { + my log "unknown called with $obj $args" + } + Users ad_proc nr_active {} { + @return number of active users (in time window) + } { + return [my array size pa] + } + Users ad_proc hits {uid} { + @param uid request key + @return Number of hits by this user (in time window) + } { + if {[my exists hits($uid)]} {return [my set hits($uid)]} else {return 0} + } + Users ad_proc last_pa {uid} { + @param uid request key + @return last peer address of the specified users + } { + if {[my exists pa($uid)]} { return [my set pa($uid)]} else { return "" } + } + Users proc last_click {uid} { + if {[my exists timestamp($uid)]} {return [my set timestamp($uid)]} else {return 0} + } + Users proc last_requests {uid} { + if {[my exists pa($uid)]} { + set urls [list] + foreach i [Users info instances] { + if {[$i exists urls($uid)]} { + foreach u [$i set urls($uid)] { lappend urls $u } + } + } + return [lsort -index 0 $urls] + } else { return "" } + } + + Users proc active_communities {} { + foreach i [Users info instances] { + lappend communities \ + [list [$i point_in_time] [$i array names in_community]] + foreach {c names} [$i array get in_community] { + lappend community($c) $names + } + } + return [array get community] + } + + Users proc nr_active_communities {} { + foreach i [Users info instances] { + foreach c [$i array names in_community] { + set community($c) 1 + } + } + set n [array size community] + return [incr n -1]; # subtract "non-community" with empty string id + } + + Users proc in_community {community_id} { + set users [list] + foreach i [Users info instances] { + if {[$i exists in_community($community_id)]} { + set time [$i point_in_time] + foreach u [$i set in_community($community_id)] { + lappend users [list $time $u] + } + } + } + return $users + } + + Users proc current_object {} { + throttler instvar timeWindow + my instvar last_mkey + set now [clock seconds] + set mkey [expr { ($now / 60) % $timeWindow}] + set obj [self]::users::$mkey + + if {$mkey ne $last_mkey} { + if {$last_mkey ne ""} {my purge_access_stats} + # create or recreate the container object for that minute + if {[my isobject $obj]} {$obj destroy} + Users create $obj -point_in_time $now + my set last_mkey $mkey + } + return $obj + } + Users proc purge_access_stats {} { + throttler instvar timeWindow + my instvar last_mkey + set time [clock seconds] + # purge stale entries (for low traffic) + set secs [expr {$timeWindow*60}] + if { $time - [[self]::users::$last_mkey point_in_time] > $secs } { + # no requests for a while; delete all objects under [self]::users:: + Object create [self]::users + } else { + # delete selectively + foreach element [[self]::users info children] { + if { [$element point_in_time] < $time - $secs } {$element destroy} + } + } + } + + Users proc community_access {requestor community_id} { + [my current_object] community_access $requestor $community_id + } + + Users instproc community_access {key community_id} { + if {![my exists user_in_community($key,$community_id)]} { + my set user_in_community($key,$community_id) 1 + my lappend in_community($community_id) $key + } + } + + Users instproc addKey {key pa url community_id} { + set class [self class] + if {[$class exists pa($key)]} { + # check, if the peer address changed + if {[$class set pa($key)] ne $pa} { + if {[catch {$class incr switches($key)}]} { + $class set switches($key) 1 + } + # log the change + set timestamp [clock format [clock seconds]] + set f [open $::logdir/switches.log a] + puts $f "$timestamp -- switch $key from\ + [$class set pa($key)] to $pa $url" + close $f + } + } + if {[catch {my incr active($key)}]} { + my set active($key) 1 + $class incrRefCount $key $pa + } + my community_access $key $community_id + set entry [list [my point_in_time] $url $pa] + if {[catch {my lappend urls($key) $entry}]} { + my set urls($key) [list $entry] + } + if {[catch {$class incr hits($key)}]} { + $class set hits($key) 1 + } + } + + Users instproc destroy {} { + foreach key [my array names active] { + [self class] decrRefCount $key [my set active($key)] + } + next + } + Users proc expSmooth {ts key} { + set mins [expr {$ts/60}] + if {[my exists expSmooth($key)]} { + foreach {_ aggval lastmins hits} [my set expSmooth($key)] break + set mindiff [expr {$mins-$lastmins}] + if {$mindiff == 0} { + incr hits + set retval [expr {$aggval*0.3 + $hits*0.7}] + } else { + set aggval [expr {$aggval*pow(0.3,$mindiff) + $hits*0.7}] + set hits 1 + } + } else { + set hits 1 + set aggval 1.0 + } + if {![info exists retval]} {set retval $aggval} + my set expSmooth($key) [list $retval $aggval $mins $hits] + return $retval + } + Users proc incrRefCount {key pa} { + if {[my exists refcount($key)]} { + my incr refcount($key) + } else { + my set refcount($key) 1 + } + my set pa($key) $pa + my set timestamp($key) [clock seconds] + } + Users proc decrRefCount {key hitcount} { + if {[my exists refcount($key)]} { + set x [my incr refcount($key) -1] + my incr hits($key) -$hitcount + if {$x < 1} { + my unset refcount($key) + my unset pa($key) + catch {my unset expSmooth($key)} + catch {my unset switches($key)} + } + } else { + my log "+++ cannot decrement refcount for '$key' by $hitcount" + } + } + Users proc perDay {} { + set ip 0; set auth 0 + foreach i [my array names timestamp] { + if {[string match *.* $i]} {incr ip} {incr auth} + } + return [list $ip $auth] + } + + Users proc perDayCleanup {} { + set secsPerDay [expr {3600*24}] + foreach i [lsort [my array names timestamp]] { + set secs [expr {[clock seconds]-[my set timestamp($i)]}] + # my log "--- $i: last click $secs secs ago" + if {$secs>$secsPerDay} { + foreach {d h m s} [clock format [expr {$secs-$secsPerDay}] \ + -format {%j %H %M %S}] break + regexp {^[0]+(.*)$} $d match d + regexp {^[0]+(.*)$} $h match h + incr d -1 + incr h -1 + my log "--- $i expired $d days $h hours $m minutes ago" + my unset timestamp($i) + } + } + after [expr {60000*60}] [list [self] [self proc]] + } + + # initialization of Users class object + Users perDayCleanup + Object create Users::users + Users set last_mkey "" + + # for debugging purposes: return all running timers + proc showTimers {} { + set _ "" + foreach t [after info] { append _ "$t [after info $t]\n" } + return $_ + } + + + set ::package_id [::Generic::package_id_from_package_key \ + xotcl-request-monitor] + ns_log notice "+++ package_id of xotcl-request-monitor is $::package_id" + + set logdir [parameter::get -package_id $::package_id \ + -parameter log-dir \ + -default [file dirname [file root [ns_config ns/parameters ServerLog]]]] + if {![file isdirectory $logdir]} {file mkdir $logdir} + +} -persistent 1 -ad_doc { + This is a small request-throttle application that handles simple + DOS-attracks on an AOL-server. A user (request key) is identified + via ipAddr or some other key, such as an authenticated userid. +

+ XOTcl Parameters for Class Throttle: +

+ The throttler is defined as a class running in a detached thread. + It can be subclassed to define e.g. different kinds of throttling policies for + different kind of request keys. Note that the throttle thread itself + does not block, only the connection thread blocks if necessary (on throttles). +

+ The controlling thread contains the classes + Users, + Throttle, + Counter, + MaxCounter, ... + @author Gustaf Neumann + @cvs-id $Id: throttle_mod-procs.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} + +throttle proc ms {-start_time} { + if {![info exists start_time]} { + set start_time [ns_conn start] + } + set t [ns_time diff [ns_time get] $start_time] + set ms [expr {[ns_time seconds $t]*1000 + [ns_time microseconds $t]/1000}] + return $ms +} + +throttle proc get_context {} { + my instvar url query requestor user pa + if {[my exists context_initialized]} return + set pa [ad_conn peeraddr] + my set community_id 0 + + if {[info exists ::ad_conn(user_id)]} { + # ordinary request, ad_conn is initialized + set requestor $::ad_conn(user_id) + set package_id [ad_conn package_id] + if {[info command dotlrn_community::get_community_id] ne "" && + $package_id ne ""} { + my set community_id [dotlrn_community::get_community_id \ + -package_id $package_id] + } + } else { + # for requests bypassing the ordinary connection setup (resources in oacs 5.2) + # we have to get the user_id by ourselves + if { [catch { + if {[info command ad_cookie] ne ""} { + # we have the xotcl-based cookie code + set cookie_list [ad_cookie get_signed_with_expr "ad_session_id"] + } else { + set cookie_list [ad_get_signed_cookie_with_expr "ad_session_id"] + } + set cookie_data [split [lindex $cookie_list 0] {,}] + set untrusted_user_id [lindex $cookie_data 1] + set requestor $untrusted_user_id + } errmsg] } { + set requestor 0 + } + } + #my log "get_context, user_id = $requestor" + + # if user not authorized, use peer address as user id + if {$requestor == 0} { + set requestor $pa + set user "client from $pa" + } else { + set user "$requestor" + } + set url [ad_conn url] + set query [ad_conn query] + if {$query ne ""} { + append url ?$query + } + #my log "+++ setting url to $url" + #show_stack + my set context_initialized 1 +} + +proc show_stack {{m 100}} { + if {[::info exists ::template::parse_level]} { + set parse_level $::template::parse_level + } else { + set parse_level "" + } + set msg "### tid=[::thread::id] <$parse_level> connected=[ns_conn isconnected] " + if {[ns_conn isconnected]} { + append msg "flags=[ad_conn flags] status=[ad_conn status] req=[ad_conn request]" + } + my log $msg + set max [info level] + if {$m<$max} {set max $m} + my log "### Call Stack (level: command)" + for {set i 0} {$i < $max} {incr i} { + if {[catch {set s [uplevel $i self]} msg]} { + set s "" + } + my log "### [format %5d -$i]:\t$s [info level [expr {-$i}]]" + } +} + +throttle ad_proc check {} { + This method should be called once per request that is monitored. + It should be called after authentication shuch we have already + the userid if the user is authenticated +} { + my instvar url requestor user pa query community_id + my get_context + + foreach {toMuch ms repeat} \ + [my throttle_check $requestor $pa $url \ + [ns_conn start] [ns_guesstype $url] $community_id] \ + break + if {$repeat} { + my add_statistics repeat $requestor $pa $url $query + return -1 + } elseif {$toMuch} { + my log "*** we have to refuse user $requestor with $toMuch requests" + my add_statistics reject $requestor $pa $url $query + return $toMuch + } elseif {$ms} { + my log "*** we have to block user $requestor for $ms ms" + my add_statistics throttle $requestor $pa $url $query + after $ms + my log "*** continue for user $requestor" + } + return 0 +} +#### +# the following procs are forwarder to the monitoring thread +# for conveniance +#### +throttle forward statistics %self do throttler %proc +throttle forward url_statistics %self do throttler %proc +throttle forward add_url_stat %self do throttler %proc +throttle forward flush_url_stats %self do throttler %proc +throttle forward report_url_stats %self do throttler %proc +throttle forward add_statistics %self do throttler %proc +throttle forward throttle_check %self do throttler %proc +throttle forward last100 %self do throttler %proc +throttle forward off %self do throttler set off 1 +throttle forward on %self do throttler set off 0 +throttle forward running %self do throttler %proc +throttle forward nr_running %self do array size running_url +throttle forward trend %self do %1 set trend +throttle forward max_values %self do %1 set stats +throttle forward purge_access_stats %self do Users %proc +throttle forward users %self do Users + +#### +# the next procs are for the filters (registered from the -init file) +#### +throttle proc postauth args { + #my log "+++ [self proc] [ad_conn url] auth ms [my ms] [ad_conn isconnected]" + set r [my check] + if {$r<0} { + ns_return 200 text/html " +

Repeated Operation

+ Operation blocked. + Don't submit the same query, while the old one is still + running...

" + return filter_return + } elseif {$r>0} { + ns_return 200 text/html " +

Invalid Operation

+ This web server is only open for interactive usage.
+ Automated copying and mirroring is not allowed!

+ Please slow down your requests...

" + return filter_return + } else { + return filter_ok + } +} +throttle proc trace args { + #my log "+++ [self proc] <$args> [ad_conn url] [my ms] [ad_conn isconnected]" + # openacs 5.2 bypasses for requests to /resources the user filter + # in these cases pre- or postauth are not called, but only trace. + # So we have to make sure we have the needed context here + my get_context + my add_url_stat [my set url] [my ms] [my set requestor] [my set pa] + my unset context_initialized + return filter_ok +} + +throttle proc community_access {community_id} { + my get_context + if {[my set community_id] eq ""} { + my users community_access [my set requestor] $community_id + } +} + +ad_proc string_truncate_middle {{-ellipsis ...} {-len 100} string} { + cut middle part of a string in case it is to long +} { + set string [string trim $string] + if {[string length $string]>$len} { + set half [expr {($len-2)/2}] + set left [string trimright [string range $string 0 $half]] + set right [string trimleft [string range $string end-$half end]] + return $left$ellipsis$right + } + return $string +} \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-procs.tcl-orig =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/tcl/Attic/throttle_mod-procs.tcl-orig,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/tcl/throttle_mod-procs.tcl-orig 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,835 @@ +############################################################################# +::xotcl::THREAD create throttle { + + Class create ThrottleStat -parameter { type requestor timestamp ip_adress url } + + Class create Throttle -parameter { + {timeWindow 10} + {timeoutMs 2000} + {startThrottle 7} + {toMuch 10} + {alerts 0} {throttles 0} {rejects 0} {repeats 0} + } + + Throttle instproc init {} { + my set off 0 + Object create [self]::stats + Object create [self]::users + next + } + + Throttle instproc add_statistics { type requestor ip_adress url query } { + set furl [expr {$query != "" ? "$url?$query" : $url}] + my incr ${type}s + #my log "++++ add_statistics -type $type -user_id $requestor " + set entry [ThrottleStat new -childof [self]::stats \ + -type $type -requestor $requestor \ + -timestamp [clock seconds] \ + -ip_adress $ip_adress -url $furl] + } + + Throttle instproc url_statistics {{-flush 0}} { + set data [[self]::stats info children] + if { [llength $data] == 0} { + return $data + } elseif {$flush} { + foreach c $data {$c destroy} + return "" + } else { + foreach stat $data { + lappend output [list [$stat type] [$stat requestor] \ + [$stat timestamp] [$stat ip_adress] [$stat url]] + } + return $output + } + } + + Throttle instproc call_statistics {} { + set l [list] + foreach t {seconds minutes hours} { + lappend l [list $t [$t set last] [$t set trend] [$t set stats]] + } + return $l + } + + Throttle instproc register_access {requestKey pa url community_id} { + set obj [Users current_object] + $obj addKey $requestKey $pa $url $community_id + Users expSmooth [$obj point_in_time] $requestKey + } + + + + Throttle instproc running {} { + my array get running_url + } + + Throttle instproc throttle_check {requestKey pa url conn_time content_type community_id} { + my instvar off + seconds ++ + + set var running_url($requestKey,$url) + # check first, whether the same user has already the same request + # issued; if yes, block this request. Caveat: some html-pages + # use the same image in many places, so we can't block it. This + # will make the sttistics for images look better than they are. + set is_image_request [string match image/* $content_type] + if {[my exists $var] && !$is_image_request && !$off} { + my log "### already $var" + return [list 0 0 1] + } else { + my set $var $conn_time + #my log "### new $var" + } + my register_access $requestKey $pa $url $community_id + + # ... the number of 14 is arbitrary. one of our single real request + # might have up to 14 subrequests (through iframes).... + if {$off || $is_image_request || [my array size running_url] < 14} { + + # less than forteen running requests, let people do what they want; + # don't throttle/block embedded images..... + return [list 0 0 0] + + } else { + + # Check, whether the last request from a user was within + # the minimum time interval. We are not keeping a full table + # of all request keys, but use an timeout triggered mechanism + # to keep only the active request keys in an associative array + + my incr alerts + if {[my exists active($requestKey)]} { + # if more than one request for this key is already active, + # return blocking time + foreach {to cnt} [my set active($requestKey)] break + set retMs [expr {$cnt>[my startThrottle] ? 500 : 0}] + # cancel the timeout + after cancel $to + } else { + set retMs 0 + set cnt 0 + } + incr cnt + # establish a new timeout + set to [after [my timeoutMs] [list [self] cancel $requestKey]] + my set active($requestKey) [list $to $cnt] + if {$cnt <= [my toMuch]} { + set cnt 0 + } + return [list $cnt $retMs 0] + } + } + + Throttle instproc statistics {} { + return " + + + + +
Number of alerts:[my alerts]
Number of throttles:[my throttles]
Number of rejects:[my rejects]
Number of repeats:[my repeats]
\n" + } + + Throttle instproc cancel {requestKey} { + # cancel a timeout and clean up active request table for this key + if {[my exists active($requestKey)]} { + after cancel [lindex [my set active($requestKey)] 0] + my unset active($requestKey) + #my log "+++ Cancel $requestKey block" + } else { + my log "+++ Cancel for $requestKey failed !!!" + } + } + + Throttle instproc active { } { + # return the currently active requests (for debugging and introspection) + return [my array get active] + } + + Throttle instproc add_url_stat {url time_used key pa} { + catch {my unset running_url($key,$url)} + #my log "### unset running_url($key,$url)" + response_time_minutes add_url_stat $url $time_used $key + } + Throttle instforward report_url_stats response_time_minutes %proc + Throttle instforward flush_url_stats response_time_minutes %proc + Throttle instforward last100 response_time_minutes %proc + Throttle create throttler + + ############################ + # A simple counter class, which is able to aggregate values in some + # higher level counters (report_to) and to keep statistics in form + # of a trend and max values) + Class create Counter -parameter { + report timeoutMs + {stats ""} {last ""} {trend ""} {c 0} {logging 0} + {nr_trend_elements 48} {nr_stats_elements 5} + } + Counter instproc ++ {} { + my incr c + } + Counter instproc end {} { + if {[my exists report]} { + [my report] incr c [my c] + } + my finalize [my c] + my c 0 + } + Counter instproc log_to_file {timestamp label value} { + if {![my logging]} return + set server [ns_info server] + set f [open $::logdir/counter.log a] + puts $f "$timestamp -- $server $label $value" + close $f + } + Counter instproc finalize {n} { + after cancel [my set to] + my instvar stats trend + # + # trend keeps nr_trend_elements most recent values + # + lappend trend $n + set lt [llength $trend] + if {$lt > [my nr_trend_elements]} { + set trend [lrange $trend [expr {$lt-[my nr_trend_elements]}] end] + } + # + # stats keeps nr_stats_elements highest values with time stamp + # + set now [clock format [clock seconds]] + lappend stats [list $now $n] + set stats [lrange [lsort -real -decreasing -index 1 $stats] 0 [my nr_stats_elements]] + # + # log if necessary + # + catch {my log_to_file $now [self] $n} + # + my set to [after [my timeoutMs] [list [self] end]] + } + + Counter instproc init {} { + my set to [after [my timeoutMs] [list [self] end]] + next + } + Counter instproc destroy {} { + after cancel [my set to] + next + } + + Counter hours -timeoutMs [expr {60000*60}] -logging 1 + Counter minutes -timeoutMs 60000 -report hours -logging 1 + Counter seconds -timeoutMs 1000 -report minutes + + Class create MaxCounter -superclass Counter -instproc end {} { + my c [Users nr_active] + if {[my exists report]} { + [my report] instvar {c rc} + if {$rc < [my c]} {set rc [my c]} + } + my finalize [my c] + my c 0 + } + + MaxCounter user_count_hours -timeoutMs [expr {60000*60}] -logging 1 + MaxCounter user_count_minutes -timeoutMs 60000 -report user_count_hours -logging 1 + + + Class create AvgCounter -superclass Counter \ + -parameter {{t 0} {atleast 1}} -instproc end {} { + if {[my c]>0} { + set avg [expr {int([my t]*1.0/[my c])}] + } else { + set avg 0 + } + if {[my exists report]} { + [my report] incr c [my c] + [my report] incr t [my t] + } + my finalize $avg + my c 0 + my t 0 + } + + Class create UrlCounter -superclass AvgCounter \ + -parameter {{truncate_check 10} {max_urls 0}} \ + -set seconds [clock seconds] \ + -instproc add_url_stat {url ms requestor} { + my instvar c + my ++ + # my log "[self proc] $url /$ms/ $requestor ($c)" + my incr t $ms + + ### set up a value for the right ordering in last 100. + ### We take the difference in seconds since start, multiply by + ### 10000 (there should be no overflow); there should be less + ### than this number requests per minute. + set now [clock seconds] + set order [expr {($now-[[self class] set seconds])*10000+$c}] + my set last100([expr {$order%99}]) [list $now $order $url $ms $requestor] + + ### Add statistics in detail + if {[my exists stat($url)]} { + my incr stat($url) $ms + my incr cnt($url) + } else { + my set stat($url) $ms + my set cnt($url) 1 + } + } -instproc last100 {} { + my array get last100 + } -instproc flush_url_stats {} { + my log "flush_url_stats" + my array unset stat + my array unset cnt + } -instproc url_stats {} { + set result [list] + foreach url [my array names stat] { + lappend result [list $url [my set stat($url)] [my set cnt($url)]] + } + set result [lsort -real -decreasing -index 1 $result] + return $result + } -instproc check_truncate_stats {} { + # truncate statistics if necessary + if {[info exists ::package_id]} { + # get values from package parameters + my max_urls [parameter::get -package_id $::package_id \ + -parameter max-url-stats -default 13] + # we use the timer to check other parameters as well here + set time_window [parameter::get -package_id $::package_id \ + -parameter time-window -default 10] + if {$time_window != [throttler timeWindow]} { + throttler timeWindow $time_window + after 0 [list Users purge_access_stats] + } + } + set max [my max_urls] + if {$max>1} { + set result [my url_stats] + set l [llength $result] + for {set i $max} {$i<$l} {incr i} { + set url [lindex [lindex $result $i] 0] + my unset stat($url) + my unset cnt($url) + } + set result [lrange $result 0 [expr {$max-1}]] + return $result + } + return "" + } -instproc report_url_stats {} { + set stats [my check_truncate_stats] + if {$stats eq ""} { + set stats [my url_stats] + } + return $stats + } -instproc finalize args { + next + # each time the timer runs out, perform the cleanup + after 0 [list [self] check_truncate_stats] + } + + + UrlCounter response_time_hours -timeoutMs [expr {60000*60}] \ + -atleast 500 -logging 1 + UrlCounter response_time_minutes -timeoutMs 60000 \ + -report response_time_hours -atleast 100 \ + -logging 1 + + # + # Class for the user tracking + + Class create Users -parameter { point_in_time } -ad_doc { + This class is responsible for the user tracking and is defined only + in a separate Tcl thread named throttle. + For each minute within the specified time-window an instance + of this class exists keeping various statistics. + When a minute ends the instance dropping out of the + time window is destroyed. The procs of this class can be + used to obtain various kinds of information. + + @author Gustaf Neumann + @cvs-id $Id: throttle_mod-procs.tcl-orig,v 1.1 2005/12/14 16:09:02 maltes Exp $ + } + Users ad_proc active {-full:switch} { + Return a list of lists containing information about current + users. If the switch 'full' is used this list contains + these users who have used the server within the + monitoring time window (per default: 10 minutes). Otherwise, + just a list of requestors (user_ids or peer addresses for unauthenticated + requests) is returned. +

+ If -full is used for each requestor the last + peer address, the last timestamp, the number of hits, a list + of values for the activity calculations and the number of ip-switches + the user is returned. +

+ The activity calculations are performed on base of an exponential smoothing + algorithm which is calculated through an aggregated value, a timestamp + (in minutes) and the number of hits in the monitored time window. + @return list with detailed user info + } { + if {$full} { + set info [list] + foreach key [my array names pa] { + set entry [list $key [my set pa($key)]] + foreach var [list timestamp hits expSmooth switches] { + set k ${var}($key) + lappend entry [expr {[my exists $k] ? [my set $k] : 0}] + } + lappend info $entry + } + return $info + } else { + return [my array names pa] + } + } + Users proc unknown { obj args } { + my log "unknown called with $obj $args" + } + Users ad_proc nr_active {} { + @return number of active users (in time window) + } { + return [my array size pa] + } + Users ad_proc hits {uid} { + @param uid request key + @return Number of hits by this user (in time window) + } { + if {[my exists hits($uid)]} {return [my set hits($uid)]} else {return 0} + } + Users ad_proc last_pa {uid} { + @param uid request key + @return last peer address of the specified users + } { + if {[my exists pa($uid)]} { return [my set pa($uid)]} else { return "" } + } + Users proc last_click {uid} { + if {[my exists timestamp($uid)]} {return [my set timestamp($uid)]} else {return 0} + } + Users proc last_requests {uid} { + if {[my exists pa($uid)]} { + set urls [list] + foreach i [Users info instances] { + if {[$i exists urls($uid)]} { + foreach u [$i set urls($uid)] { lappend urls $u } + } + } + return [lsort -index 0 $urls] + } else { return "" } + } + + Users proc active_communities {} { + foreach i [Users info instances] { + lappend communities \ + [list [$i point_in_time] [$i array names in_community]] + foreach {c names} [$i array get in_community] { + lappend community($c) $names + } + } + return [array get community] + } + + Users proc nr_active_communities {} { + foreach i [Users info instances] { + foreach c [$i array names in_community] { + set community($c) 1 + } + } + set n [array size community] + return [incr n -1]; # subtract "non-community" with empty string id + } + + Users proc in_community {community_id} { + set users [list] + foreach i [Users info instances] { + if {[$i exists in_community($community_id)]} { + set time [$i point_in_time] + foreach u [$i set in_community($community_id)] { + lappend users [list $time $u] + } + } + } + return $users + } + + Users proc current_object {} { + throttler instvar timeWindow + my instvar last_mkey + set now [clock seconds] + set mkey [expr { ($now / 60) % $timeWindow}] + set obj [self]::users::$mkey + + if {$mkey ne $last_mkey} { + if {$last_mkey ne ""} {my purge_access_stats} + # create or recreate the container object for that minute + if {[my isobject $obj]} {$obj destroy} + Users create $obj -point_in_time $now + my set last_mkey $mkey + } + return $obj + } + Users proc purge_access_stats {} { + throttler instvar timeWindow + my instvar last_mkey + set time [clock seconds] + # purge stale entries (for low traffic) + set secs [expr {$timeWindow*60}] + if { $time - [[self]::users::$last_mkey point_in_time] > $secs } { + # no requests for a while; delete all objects under [self]::users:: + Object create [self]::users + } else { + # delete selectively + foreach element [[self]::users info children] { + if { [$element point_in_time] < $time - $secs } {$element destroy} + } + } + } + + Users proc community_access {requestor community_id} { + [my current_object] community_access $requestor $community_id + } + + Users instproc community_access {key community_id} { + if {![my exists user_in_community($key,$community_id)]} { + my set user_in_community($key,$community_id) 1 + my lappend in_community($community_id) $key + } + } + + Users instproc addKey {key pa url community_id} { + set class [self class] + if {[$class exists pa($key)]} { + # check, if the peer address changed + if {[$class set pa($key)] ne $pa} { + if {[catch {$class incr switches($key)}]} { + $class set switches($key) 1 + } + # log the change + set timestamp [clock format [clock seconds]] + set f [open $::logdir/switches.log a] + puts $f "$timestamp -- switch $key from\ + [$class set pa($key)] to $pa $url" + close $f + } + } + if {[catch {my incr active($key)}]} { + my set active($key) 1 + $class incrRefCount $key $pa + } + my community_access $key $community_id + set entry [list [my point_in_time] $url $pa] + if {[catch {my lappend urls($key) $entry}]} { + my set urls($key) [list $entry] + } + if {[catch {$class incr hits($key)}]} { + $class set hits($key) 1 + } + } + + Users instproc destroy {} { + foreach key [my array names active] { + [self class] decrRefCount $key [my set active($key)] + } + next + } + Users proc expSmooth {ts key} { + set mins [expr {$ts/60}] + if {[my exists expSmooth($key)]} { + foreach {_ aggval lastmins hits} [my set expSmooth($key)] break + set mindiff [expr {$mins-$lastmins}] + if {$mindiff == 0} { + incr hits + set retval [expr {$aggval*0.3 + $hits*0.7}] + } else { + set aggval [expr {$aggval*pow(0.3,$mindiff) + $hits*0.7}] + set hits 1 + } + } else { + set hits 1 + set aggval 1.0 + } + if {![info exists retval]} {set retval $aggval} + my set expSmooth($key) [list $retval $aggval $mins $hits] + return $retval + } + Users proc incrRefCount {key pa} { + if {[my exists refcount($key)]} { + my incr refcount($key) + } else { + my set refcount($key) 1 + } + my set pa($key) $pa + my set timestamp($key) [clock seconds] + } + Users proc decrRefCount {key hitcount} { + if {[my exists refcount($key)]} { + set x [my incr refcount($key) -1] + my incr hits($key) -$hitcount + if {$x < 1} { + my unset refcount($key) + my unset pa($key) + catch {my unset expSmooth($key)} + catch {my unset switches($key)} + } + } else { + my log "+++ cannot decrement refcount for '$key' by $hitcount" + } + } + Users proc perDay {} { + set ip 0; set auth 0 + foreach i [my array names timestamp] { + if {[string match *.* $i]} {incr ip} {incr auth} + } + return [list $ip $auth] + } + + Users proc perDayCleanup {} { + set secsPerDay [expr {3600*24}] + foreach i [lsort [my array names timestamp]] { + set secs [expr {[clock seconds]-[my set timestamp($i)]}] + # my log "--- $i: last click $secs secs ago" + if {$secs>$secsPerDay} { + foreach {d h m s} [clock format [expr {$secs-$secsPerDay}] \ + -format {%j %H %M %S}] break + regexp {^[0]+(.*)$} $d match d + regexp {^[0]+(.*)$} $h match h + incr d -1 + incr h -1 + my log "--- $i expired $d days $h hours $m minutes ago" + my unset timestamp($i) + } + } + after [expr {60000*60}] [list [self] [self proc]] + } + + # initialization of Users class object + Users perDayCleanup + Object create Users::users + Users set last_mkey "" + + # for debugging purposes: return all running timers + proc showTimers {} { + set _ "" + foreach t [after info] { append _ "$t [after info $t]\n" } + return $_ + } + + + set ::package_id [::Generic::package_id_from_package_key \ + xotcl-request-monitor] + ns_log notice "+++ package_id of xotcl-request-monitor is $::package_id" + + set logdir [parameter::get -package_id $::package_id \ + -parameter log-dir \ + -default [file dirname [file root [ns_config ns/parameters ServerLog]]]] + if {![file isdirectory $logdir]} {file mkdir $logdir} + +} -persistent 1 -ad_doc { + This is a small request-throttle application that handles simple + DOS-attracks on an AOL-server. A user (request key) is identified + via ipAddr or some other key, such as an authenticated userid. +

+ XOTcl Parameters for Class Throttle: +

+ The throttler is defined as a class running in a detached thread. + It can be subclassed to define e.g. different kinds of throttling policies for + different kind of request keys. Note that the throttle thread itself + does not block, only the connection thread blocks if necessary (on throttles). +

+ The controlling thread contains the classes + Users, + Throttle, + Counter, + MaxCounter, ... + @author Gustaf Neumann + @cvs-id $Id: throttle_mod-procs.tcl-orig,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} + +throttle proc ms {-start_time} { + if {![info exists start_time]} { + set start_time [ns_conn start] + } + set t [ns_time diff [ns_time get] $start_time] + set ms [expr {[ns_time seconds $t]*1000 + [ns_time microseconds $t]/1000}] + return $ms +} + +throttle proc get_context {} { + my instvar url query requestor user pa + if {[my exists context_initialized]} return + set pa [ad_conn peeraddr] + my set community_id 0 + + if {[info exists ::ad_conn(user_id)]} { + # ordinary request, ad_conn is initialized + set requestor $::ad_conn(user_id) + if {[info command dotlrn_community::get_community_id] ne ""} { + my set community_id [dotlrn_community::get_community_id \ + -package_id [ad_conn package_id]] + } + } else { + # for requests bypassing the ordinary connection setup (resources in oacs 5.2) + # we have to get the user_id by ourselves + if { [catch { + if {[info command ad_cookie] ne ""} { + # we have the xotcl-based cookie code + set cookie_list [ad_cookie get_signed_with_expr "ad_session_id"] + } else { + set cookie_list [ad_get_signed_cookie_with_expr "ad_session_id"] + } + set cookie_data [split [lindex $cookie_list 0] {,}] + set untrusted_user_id [lindex $cookie_data 1] + set requestor $untrusted_user_id + } errmsg] } { + set requestor 0 + } + } + #my log "get_context, user_id = $requestor" + + # if user not authorized, use peer address as user id + if {$requestor == 0} { + set requestor $pa + set user "client from $pa" + } else { + set user "$requestor" + } + set url [ad_conn url] + set query [ad_conn query] + if {$query ne ""} { + append url ?$query + } + #my log "+++ setting url to $url" + #show_stack + my set context_initialized 1 +} + +proc show_stack {{m 100}} { + if {[::info exists ::template::parse_level]} { + set parse_level $::template::parse_level + } else { + set parse_level "" + } + set msg "### tid=[::thread::id] <$parse_level> connected=[ns_conn isconnected] " + if {[ns_conn isconnected]} { + append msg "flags=[ad_conn flags] status=[ad_conn status] req=[ad_conn request]" + } + my log $msg + set max [info level] + if {$m<$max} {set max $m} + my log "### Call Stack (level: command)" + for {set i 0} {$i < $max} {incr i} { + if {[catch {set s [uplevel $i self]} msg]} { + set s "" + } + my log "### [format %5d -$i]:\t$s [info level [expr {-$i}]]" + } +} + +throttle ad_proc check {} { + This method should be called once per request that is monitored. + It should be called after authentication shuch we have already + the userid if the user is authenticated +} { + my instvar url requestor user pa query community_id + my get_context + + foreach {toMuch ms repeat} \ + [my throttle_check $requestor $pa $url \ + [ns_conn start] [ns_guesstype $url] $community_id] \ + break + if {$repeat} { + my add_statistics repeat $requestor $pa $url $query + return -1 + } elseif {$toMuch} { + my log "*** we have to refuse user $requestor with $toMuch requests" + my add_statistics reject $requestor $pa $url $query + return $toMuch + } elseif {$ms} { + my log "*** we have to block user $requestor for $ms ms" + my add_statistics throttle $requestor $pa $url $query + after $ms + my log "*** continue for user $requestor" + } + return 0 +} +#### +# the following procs are forwarder to the monitoring thread +# for conveniance +#### +throttle forward statistics %self do throttler %proc +throttle forward url_statistics %self do throttler %proc +throttle forward add_url_stat %self do throttler %proc +throttle forward flush_url_stats %self do throttler %proc +throttle forward report_url_stats %self do throttler %proc +throttle forward add_statistics %self do throttler %proc +throttle forward throttle_check %self do throttler %proc +throttle forward last100 %self do throttler %proc +throttle forward off %self do throttler set off 1 +throttle forward on %self do throttler set off 0 +throttle forward running %self do throttler %proc +throttle forward nr_running %self do array size running_url +throttle forward trend %self do %1 set trend +throttle forward max_values %self do %1 set stats +throttle forward purge_access_stats %self do Users %proc +throttle forward users %self do Users + +#### +# the next procs are for the filters (registered from the -init file) +#### +throttle proc postauth args { + #my log "+++ [self proc] [ad_conn url] auth ms [my ms] [ad_conn isconnected]" + set r [my check] + if {$r<0} { + ns_return 200 text/html " +

Repeated Operation

+ Operation blocked. + Don't submit the same query, while the old one is still + running...

" + return filter_return + } elseif {$r>0} { + ns_return 200 text/html " +

Invalid Operation

+ This web server is only open for interactive usage.
+ Automated copying and mirroring is not allowed!

+ Please slow down your requests...

" + return filter_return + } else { + return filter_ok + } +} +throttle proc trace args { + #my log "+++ [self proc] <$args> [ad_conn url] [my ms] [ad_conn isconnected]" + # openacs 5.2 bypasses for requests to /resources the user filter + # in these cases pre- or postauth are not called, but only trace. + # So we have to make sure we have the needed context here + my get_context + my add_url_stat [my set url] [my ms] [my set requestor] [my set pa] + my unset context_initialized + return filter_ok +} + +throttle proc community_access {community_id} { + my get_context + if {[my set community_id] eq ""} { + my users community_access [my set requestor] $community_id + } +} + +ad_proc string_truncate_middle {{-ellipsis ...} {-len 100} string} { + cut middle part of a string in case it is to long +} { + set string [string trim $string] + if {[string length $string]>$len} { + set half [expr {($len-2)/2}] + set left [string trimright [string range $string 0 $half]] + set right [string trimleft [string range $string end-$half end]] + return $left$ellipsis$right + } + return $string +} \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/active-communities.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/active-communities.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/active-communities.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,5 @@ + +@title;noquote@ +@context;noquote@ + +@t1;noquote@ Index: openacs-4/packages/xotcl-request-monitor/www/active-communities.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/active-communities.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/active-communities.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,33 @@ +ad_page_contract { + Displays active commnities + + @author Gustaf Neumann + + @cvs-id $id$ +} -query { + {orderby:optional "count,desc"} +} -properties { + title:onevalue + context:onevalue +} + +set title "Active Communities" +set context [list "Active Communities"] + +TableWidget t1 \ + -columns { + AnchorField community -label Community -orderby community + Field count -label Count -orderby count + } + +foreach {att order} [split $orderby ,] break +t1 orderby -order [expr {$order eq "asc" ? "increasing" : "decreasing"}] $att + +foreach {community_id users} [throttle users active_communities] { + if {$community_id eq ""} continue + t1 add \ + -community [dotlrn_community::get_community_name $community_id] \ + -community.href [export_vars -base users-in-community {community_id}] \ + -count [llength [lsort -unique [eval concat $users]]] +} +set t1 [t1 asHTML] \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/flush-url-statistics.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/flush-url-statistics.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/flush-url-statistics.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,11 @@ +ad_page_contract { + delete a revision of the content repository + + @author Gustaf Neumann (gustaf.neumann@wu-wien.ac.at) + @creation-date Oct 23, 2005 + @cvs-id $Id: flush-url-statistics.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} { +} + +throttle flush_url_stats +ad_returnredirect stat-details \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/index.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/index.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,55 @@ + +@title@ + + + + + + + + + + + + + + +
Active Users:@active_user_string;noquote@
Current System Activity:@current_system_activity@
Current System Load:@current_load@
Current Avg Response Time/sec:@current_response@
@running@ Request(s) + currently running, Aggregated URL Statistics, + Last 100 Requests, + Throttle Statistics +
+ + + + +@views_trend;noquote@ + + +@users_trend;noquote@ + + +@response_trend;noquote@ + + +@throttle_stats;noquote@
+ +Detailed Throttle statistics +

Page View Statistics

Active Users

Avg. Response Time in milliseconds

Throttle Statistics

+
+ +

Page View Statistics

+
@views_trend;noquote@

+ +

Active Users

+
@users_trend;noquote@

+ +

Avg. Response Time in milliseconds

+
@response_trend;noquote@
+ +
@throttle_stats;noquote@
+Detailed Throttle statistics + + Index: openacs-4/packages/xotcl-request-monitor/www/index.adp-gn =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/index.adp-gn,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/index.adp-gn 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,32 @@ + +@title@ + + + + + + + + + + + +
@active_user_label;noquote@@active_user_string@
Current System Activity:@current_system_activity@
Current System Load:@current_load@
Current Avg Response Time/sec:@current_response@
@running@ Request(s) + currently running, aggregated URL Statistics, + last 100 requests, + Throttle statistics +
+ +
+ +

Page View Statistics

+
@views_trend;noquote@

+ +

Active Users

+
@users_trend;noquote@

+ +

Avg. Response Time in milliseconds

+
@response_trend;noquote@
+ +
@throttle_stats;noquote@
+Detailed Throttle statistics Index: openacs-4/packages/xotcl-request-monitor/www/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/index.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/index.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,268 @@ +ad_page_contract { + present usage statistics, active users, etc + + @author Gustaf Neumann + @cvs-id $Id: index.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} -query { + {jsGraph 1} +} -properties { + title:onevalue + context:onevalue + active_users_10 + current_system_activity + current_load + current_response + views_trend + users_trend + response_trend + throttle_stats +} + +set title "Performance statistics" + +# compute the average of the last n values (or less, if +# not enough values are given) +proc avg_last_n {list n var} { + upvar $var cnt + set total 0.0 + set list [lrange $list end-[incr n -1] end] + foreach d $list { set total [expr {$total+$d}] } + set cnt [llength $list] + return [expr {$cnt > 0 ? $total*0.001/$cnt : 0}] +} + + +# collect current system statistics +proc currentSystemLoad {} { + return [exec "/usr/bin/uptime"] +} + +# collect current response time (per minute and hour) +proc currentResponseTime {} { + set tm [throttle trend response_time_minutes] + set hours [throttle trend response_time_hours] + if { $tm == "" } { + set ::server_running "seconds" + return "NO DATA" + } + set avg_half_hour [avg_last_n $tm 30 cnt] + if {$cnt > 0} { + set minstat "[format %4.2f $avg_half_hour] (last $cnt minutes), " + } else { + set minstat "" + } + if {[llength $tm]>0} { + set lminstat "[format %4.2f [expr {[lindex $tm end]/1000.0}]] (last minute), " + } else { + set lminstat "" + } + if {[llength $hours]>0} { + set avg_last_day [avg_last_n $hours 24 cnt] + set hourstat "[format %4.2f [expr {[lindex $hours end]/1000.0}]] (last hour), " + append hourstat "[format %4.2f $avg_last_day] (last $cnt hours)" + set server_running "$cnt hours" + } else { + if {[llength $tm]>0} { + set dummy [avg_last_n $tm 60 cnt] + set server_running "$cnt minutes" + } else { + set server_running "1 minute" + } + set hourstat "" + } + set ::server_running $server_running + return [list $lminstat $minstat $hourstat] +} + +# collect figures for views per second (when statistics are applied +# only on views) +proc currentViews {} { + set vm [throttle trend minutes] + set um [throttle trend user_count_minutes] + if { $vm == "" } { return "NO DATA" } + set views_per_sec [expr {[lindex $vm end]/60.0}] + ns_log notice "um='$um' vm='$vm' expr {60.0*$views_per_sec/[lindex $um end]}" + set views_per_min_per_user [expr {60.0*$views_per_sec/[lindex $um end]}] + set view_time [expr {$views_per_min_per_user>0 ? + " avg. view time: [format %4.1f [expr {60.0/$views_per_min_per_user}]]" : ""}] + return "[format %4.1f $views_per_sec] views/sec, [format %4.2f $views_per_min_per_user] views/min/user, $view_time" +} + + +if {$jsGraph} { + # use javascript graphics + + # draw a graph in form of an html table of with 500 pixels + proc graph {values label type} { + + switch $type { + "Second" { set delta "D.XGridDelta=10000;\n" } + "Minute" { set delta "D.XGridDelta=600000;\n" } + default { set delta ""} + } + + set max 1 + foreach v $values {if {$v>$max} {set max $v}} + + set size [llength $values] + if {$size<12} { + set values [concat [split [string repeat 0 [expr {12-$size}]] ""] $values] + set size [llength $values] + } + + set end [clock format [clock seconds] -format "%Y,%m,%d,%H,%M,%S"] + set begin [clock format [clock scan "-$size $type"] -format "%Y,%m,%d,%H,%M,%S"] + #ns_log Notice "begin: $begin, end: $end, $size $type" + + set diagram [subst {\n" + return "
\n$diagram\n
" + } + + + + proc counterTable {label objlist} { + foreach {t l} $objlist { + set trend [throttle trend $t] + append text [subst { + [graph $trend "$label per $l" $l] + + + }] + set c 1 + foreach v [throttle max_values $t] { + incr c + switch $t { + minutes {set rps "([format %5.2f [expr {[lindex $v 1]/60.0}]] rps)"} + hours {set rps "([format %5.2f [expr {[lindex $v 1]/(60*60.0)}]] rps)"} + default {set rps ""} + } + set cl [expr {$c%2==0?"list-even":"list-odd"}] + append text [subst { + + + }] + } + append text "
Max
[lindex $v 0][lindex $v 1] $rps
\n\n" + } + return $text + } + +} else { + # no javascript graphics, use poor men's approach... + + # draw a graph in form of an html table of with 500 pixels + proc graph values { + set max 1 + foreach v $values {if {$v>$max} {set max $v}} + set graph "\n" + foreach v $values { + set bar "
" + append graph "
\n" + } + append graph "
$bar
\n" + return $graph + } + + # build an HTML table from statistics of monitor thread + proc counterTable {label objlist} { + append text "" \ + "" + foreach {t l} $objlist { + set trend [throttle trend $t] + append text [subst { + + + " + } + append text "
TrendMax
$label per
$l
[graph $trend]$trend + + }] + set c 1 + foreach v [throttle max_values $t] { + incr c + switch $t { + minutes {set rps "([format %5.2f [expr {[lindex $v 1]/60.0}]] rps)"} + hours {set rps "([format %5.2f [expr {[lindex $v 1]/(60*60.0)}]] rps)"} + default {set rps ""} + } + set bg [expr {$c%2==0?"white":"#EAF2FF"}] + append text " + " + } + append text "
[lindex $v 0][lindex $v 1] $rps

" + } +} + +# set variables for template +set views_trend [counterTable Views [list seconds Second minutes Minute hours Hour]] +set users_trend [counterTable Users [list user_count_minutes Minute user_count_hours Hour]] +set response_trend [counterTable "Avg. Response
Time" \ + [list response_time_minutes Minute response_time_hours Hour]] + +set current_response [join [currentResponseTime] " "] +set current_load [currentSystemLoad] +set running [throttle nr_running] +if {![catch {ns_conn contentsentlength}]} { + append running /[bgdelivery nr_running] +} + +if {[string compare "" [info command ::tlf::system_activity]]} { + array set server_stats [::tlf::system_activity] + set current_exercise_activity $server_stats(activity) + set current_system_activity "$server_stats(activity) exercises last 15 mins, " +} else { + set current_system_activity "" +} +append current_system_activity \n[currentViews] + +set active_users_10 [throttle users nr_active] +set throttle_stats [throttle statistics] +set active24 [throttle users perDay] +set activeUsers24 [lindex $active24 1] +set activeIP24 [lindex $active24 0] +set activeTotal24 [expr {$activeUsers24 + $activeIP24}] + +if {[info command ::dotlrn_community::get_community_id] ne ""} { + set nr [throttle users nr_active_communities] + set active_community_string "in $nr communities " +} else { + set active_community_string "" +} + +set active_user_string "$active_users_10 users $active_community_string active in last 10 minutes, $activeUsers24 in last $::server_running ($activeTotal24 total)" +set jsGraph [expr {!$jsGraph}] +set toggle_graphics_url [export_vars -base [ad_conn url] {jsGraph}] +set jsGraph [expr {!$jsGraph}] \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/index.tcl-gn =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/Attic/index.tcl-gn,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/index.tcl-gn 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,187 @@ +ad_page_contract { + present usage statistics, active users, etc + + @author Gustaf Neumann + @cvs-id $Id: index.tcl-gn,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} -properties { + title:onevalue + context:onevalue + active_user_label + active_users_10 + current_system_activity + current_load + current_response + views_trend + users_trend + response_trend + throttle_stats +} + +set title "Performance statistics" + +# draw a graph in form of an html table of with 500 pixels +proc graph values { + set max 1 + foreach v $values {if {$v>$max} {set max $v}} + set graph "\n" + foreach v $values { + ns_log notice "540*$v/$max" + set bar "
" + append graph "
\n" + } + append graph "
$bar
\n" + return $graph +} + +# compute the average of the last n values (or less, if +# not enough values are given) +proc avg_last_n {list n var} { + upvar $var cnt + set total 0.0 + set list [lrange $list end-[incr n -1] end] + foreach d $list { set total [expr {$total+$d}] } + set cnt [llength $list] + return [expr {$cnt > 0 ? $total*0.001/$cnt : 0}] +} + + +# collect current system statistics +proc currentSystemLoad {} { + return [lindex [split [exec "/usr/bin/w"] \n] 0] +} + +# collect current response time (per minute and hour) +proc currentResponseTime {} { + set tm [throttle trend response_time_minutes] + set hours [throttle trend response_time_hours] + ns_log notice "trend = <$tm>" + if { $tm == "" } { + set ::server_running "seconds" + return "NO DATA" + } + set avg_half_hour [avg_last_n $tm 30 cnt] + if {$cnt > 0} { + set minstat "[format %4.2f $avg_half_hour] (last $cnt minutes), " + } else { + set minstat "" + } + if {[llength $tm]>0} { + set lminstat "[format %4.2f [expr {[lindex $tm end]/1000.0}]] (last minute), " + } else { + set lminstat "" + } + if {[llength $hours]>0} { + set avg_last_day [avg_last_n $hours 24 cnt] + set hourstat "[format %4.2f [expr {[lindex $hours end]/1000.0}]] (last hour), " + append hourstat "[format %4.2f $avg_last_day] (last $cnt hours)" + set server_running "$cnt hours" + } else { + if {[llength $tm]>0} { + set dummy [avg_last_n $tm 60 cnt] + set server_running "$cnt minutes" + } else { + set server_running "1 minute" + } + set hourstat "" + } + set ::server_running $server_running + return [list $lminstat $minstat $hourstat] +} + +# collect figures for views per second (when statistics are applied +# only on views) +proc currentViews {} { + set vm [throttle trend minutes] + set um [throttle trend user_count_minutes] + if { $vm == "" } { return "NO DATA" } + set views_per_sec [expr {[lindex $vm end]/60.0}] + set views_per_min_per_user [expr {60.0*$views_per_sec/[lindex $um end]}] + set view_time [expr {$views_per_min_per_user>0 ? + " avg. view time: [format %4.1f [expr {60.0/$views_per_min_per_user}]]" : ""}] + return "[format %4.1f $views_per_sec] views/sec, [format %4.2f $views_per_min_per_user] views/min/user, $view_time" +} + + +# build an HTML table from statistics of monitor thread + +proc counterTable {label objlist} { + append text "" \ + "" + foreach {t l} $objlist { + set trend [throttle trend $t] + append text \ + "" \ + "" \ + "" + } + append text "
TrendMax
$label per
$l
[graph $trend]$trend" \ + "\n" + set c 1 + foreach v [throttle max_values $t] { + incr c + switch $t { + minutes {set rps "([format %5.2f [expr {[lindex $v 1]/60.0}]] rps)"} + hours {set rps "([format %5.2f [expr {[lindex $v 1]/(60*60.0)}]] rps)"} + default {set rps ""} + } + set bg [expr {$c%2==0?"white":"#EAF2FF"}] + append text " + " + } + append text "
[lindex $v 0][lindex $v 1] $rps

" +} + +# set variables for template +set views_trend [counterTable Views [list seconds Second minutes Minute hours Hour]] +set users_trend [counterTable Users [list user_count_minutes Minute user_count_hours Hour]] +set response_trend [counterTable "Avg. Response
Time" \ + [list response_time_minutes Minute response_time_hours Hour]] +set current_response [join [currentResponseTime] " "] +set current_load [currentSystemLoad] +set running [throttle nr_running] + +if {[string compare "" [info command ::tlf::system_activity]]} { + array set server_stats [::tlf::system_activity] + set current_exercise_activity $server_stats(activity) + set current_system_activity "$server_stats(activity) exercises last 15 mins, " +} else { + set current_system_activity "" +} +append current_system_activity \n[currentViews] + +set active_users_10 [throttle users total] +set throttle_stats [throttle statistics] +set active24 [throttle users perDay] +set activeUsers24 [lindex $active24 1] +set activeIP24 [lindex $active24 0] +set activeTotal24 [expr {$activeUsers24 + $activeIP24}] +set active_user_string "$active_users_10 active users in last 10 minutes, $activeUsers24 in last $::server_running ($activeTotal24 total)" +set current_url [ns_conn url] +regexp {^(.*/)[^/]*$} $current_url match current_path +set active_user_label "Active Users:" + +# use template in OACS or HTML table with plain AS +if {[string compare "" [info command ad_return_template]]} { + ad_return_template +} else { + ns_return 200 text/html [subst -nobackslash { + System Statistics + + + + + + +
$active_user_label$active_users_10
Current System Activity:$current_system_activity
Current System Load:$current_load
Current Avg Response Time/sec:$current_response
Details
+
+

Page View Statistics

+
$views_trend

+

Active Users

+
$users_trend

+

Avg. Response Time in milliseconds

+
$response_trend
+ $throttle_stats + + }] +} Index: openacs-4/packages/xotcl-request-monitor/www/last-requests.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/last-requests.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/last-requests.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,8 @@ + +@title;noquote@ +@context;noquote@ + +

@user_string;noquote@

+
+@t1;noquote@ +
Index: openacs-4/packages/xotcl-request-monitor/www/last-requests.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/last-requests.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/last-requests.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,86 @@ +ad_page_contract { + Displays last requests of a user + + @author Gustaf Neumann (adapted for interaction with controlling thread) + @cvs-id $Id: last-requests.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} -query { + request_key + {all:optional 1} + {orderby:optional} +} -properties { + title:onevalue + context:onevalue + user_string:onevalue +} + +set title "Last Requests of " +set context [list "Last Requests"] +set hide_patterns [parameter::get -parameter hide-requests -default {*.css}] + +if {[string first . $request_key] > 0} { + set user_string $request_key +} else { + acs_user::get -user_id $request_key -array user + set user_string "$user(first_names) $user(last_name)" + set tmp_url [acs_community_member_url -user_id $request_key] + append user_string " ($request_key)" +} + +append title $user_string +set admin_p [acs_user::site_wide_admin_p] +if {!$admin_p} { + ad_return_warning "Insufficient Permissions" \ + "Only side wide admins are allowed to view this page!" + ad_script_abort +} + +set label(0) show_filtered +set tooltip(0) "Show filtered values" +set label(1) show_all +set tooltip(1) "Show all values" +set all [expr {!$all}] +set url [export_vars -base [ad_conn url] {request_key all}] + +TableWidget t1 \ + -actions [subst { + Action new -label "$label($all)" -url $url -tooltip "$tooltip($all)" + }] \ + -columns { + Field time -label "Time" + Field timediff -label "Seconds ago" -html { align right } + Field url -label "Url" + Field pa -label "Peer Address" + } \ + -no_data "no requests for this user recorded" + +set all [expr {!$all}] +set requests [throttle users last_requests $request_key] +set last_timestamp [lindex [lindex $requests end] 0] + +set hidden 0 +foreach element [lsort -index 0 -decreasing $requests] { + foreach {timestamp url pa} $element break + if {!$all} { + set exclude 0 + foreach pattern $hide_patterns { + if {[string match $pattern $url]} { + set exclude 1 + incr hidden + break + } + } + if {$exclude} continue + } + set diff [expr {$last_timestamp-$timestamp}] + set url [string_truncate_middle -len 70 $url] + t1 add -time [clock format $timestamp] \ + -timediff $diff \ + -url $url \ + -pa $pa +} + +set user_string "$hidden requests hidden." +if {$hidden>0} { + append user_string " (Patterns: $hide_patterns)" +} +set t1 [t1 asHTML] Index: openacs-4/packages/xotcl-request-monitor/www/last100.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/last100.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/last100.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,5 @@ + +@title;noquote@ +@context;noquote@ + +
@t1;noquote@
Index: openacs-4/packages/xotcl-request-monitor/www/last100.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/last100.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/last100.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,52 @@ +ad_page_contract { + Displays last 100 requests in the system + + @author Gustaf Neumann + + @cvs-id $id +} -query { + {orderby:optional "time,desc"} +} -properties { + title:onevalue + context:onevalue +} + +set title "Last 100 Requests" +set context [list "Last 100 Requests"] +set stat [list] +foreach {key value} [throttle last100] {lappend stat $value} + +Class CustomField -volatile \ + -instproc render-data {row} { + html::div -style { + border: 1px solid #a1a5a9; padding: 0px 5px 0px 5px; background: #e2e2e2} { + html::t [$row set [my name]] + } + } + +TableWidget t1 -volatile \ + -columns { + Field time -label "Time" -orderby time -mixin ::template::CustomField + AnchorField user -label "Userid" -orderby user + Field ms -label "Ms" -orderby ms + Field url -label "URL" -orderby url + } + +foreach {att order} [split $orderby ,] break +t1 orderby -order [expr {$order eq "asc" ? "increasing" : "decreasing"}] $att + +foreach l $stat { + foreach {timestamp c url ms requestor} $l break + if {[string first . $requestor] > 0} { + set user_string $requestor + } else { + acs_user::get -user_id $requestor -array user + set user_string "$user(first_names) $user(last_name)" + } + t1 add -time [clock format $timestamp -format "%H:%M:%S"] \ + -user $user_string \ + -user.href [export_vars -base last-requests {{request_key $requestor}}] \ + -ms $ms \ + -url $url +} +set t1 [t1 asHTML] \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/last101.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/last101.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/last101.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,166 @@ +ad_page_contract { + Displays last 100 requests in the system + + @author Gustaf Neumann + + @cvs-id $id +} -query { + {orderby:optional "time,desc"} +} -properties { + title:onevalue + context:onevalue +} + +set title "Last 100 Requests" +set context [list "Last 100 Requests"] +set stat [list] +foreach {key value} [throttle last100] {lappend stat $value} + +Class CustomField -volatile \ + -instproc render-data {row} { + html::div -style { + border: 1px solid #a1a5a9; padding: 0px 5px 0px 5px; background: #e2e2e2} { + html::t [$row set [my name]] + } + } + +TableWidget t1 -volatile \ + -columns { + Field time -label "Time" -orderby time -mixin ::template::CustomField + AnchorField user -label "Userid" -orderby user + Field ms -label "Ms" -orderby ms + Field url -label "URL" -orderby url + } + +foreach {att order} [split $orderby ,] break +t1 orderby -order [expr {$order eq "asc" ? "increasing" : "decreasing"}] $att + +foreach l $stat { + foreach {timestamp c url ms requestor} $l break + if {[string first . $requestor] > 0} { + set user_string $requestor + } else { + acs_user::get -user_id $requestor -array user + set user_string "$user(first_names) $user(last_name)" + } + t1 add -time [clock format $timestamp -format "%H:%M:%S"] \ + -user $user_string \ + -user.href [export_vars -base last-requests {{request_key $requestor}}] \ + -ms $ms \ + -url $url +} + + + +Object instproc asHTML {{-master defaultMaster} -page:switch} { + require_html_procs + dom createDocument html doc + set root [$doc documentElement] + if {!$page} { + $root appendFromScript {my render} + return [[$root childNode] asHTML] + } else { + set slave [$master decorate $root] + $slave appendFromScript {my render} + ns_return 200 text/html [$root asHTML] + } +} + +Object ::pageMaster -proc decorate {node} { + $node appendFromScript { + html::head { + html::title {html::t "XOTcl Request Monitor"} + html::link -rel stylesheet -type text/css -media all -href \ + /resources/acs-developer-support/acs-developer-support.css + html::link -rel stylesheet -type text/css -media all -href \ + /resources/acs-templating/lists.css + html::link -rel stylesheet -type text/css -media all -href \ + /resources/acs-templating/forms.css + html::link -rel stylesheet -type text/css -media all -href \ + /resources/acs-subsite/default-master.css + html::link -rel stylesheet -type text/css -media all -href \ + /resources/dotlrn/dotlrn-toolbar.css + html::script -type "text/javascript" -src "/resources/acs-subsite/core.js" \ + -language "javascript" {} + html::link -rel "shortcut icon" \ + -href "/resources/theme-selva/Selva/default/images/myicon.ico" + html::link -rel "stylesheet" -type "text/css" \ + -href "/resources/theme-selva/Selva/default/Selva.css" -media "all" + } + html::body { + html::div -id wrapper { + html::div -id header { + html::img -src /resources/theme-selva/Selva/images/dotLRN-logo.gif \ + -alt Logo + } + html::br + html::div -id site-header { + html::div -id breadcrumbs { + html::div -id context-bar { + html::a -href / {html::t "Main Site"} + html::t -disableOutputEscaping "»\n" + html::a -href "/request-monitor" {html::t "XOTcl Request Monitor"} + html::t -disableOutputEscaping "»\n" + html::t [my set context] + html::div -style "clear:both;" + } + html::div -id status { + html::div -class "action-list users-online" { + html::a -href "/shared/whos-online" { + html::t "1 member online" + } + html::t "|" + html::a -href "/register/logout" \ + -title "Von yourdomain Network abmelden" { + html::t Abmelden + } + } + html::div -class "user-greeting" { + html::t "Willkommen, Gustaf Neumann! |" + } + } + } + } ;# end of site header + html::div -id "youarehere" { + html::t [my set title] + } + html::br + html::div -id "portal-navigation" { + html::ul { + html::li {html::a -href "/dotlrn/" {html::t "My Space"}} + html::li {html::a -href "/theme-selva/courses" {html::t "Courses"}} + html::li {html::a -href "/theme-selva/communities" {html::t "Communities"}} + html::li {html::a -href "/pvt/home" {html::t "Einstellungen"}} + html::li {html::a -href "/dotlrn/control-panel" {html::t "Tools"}} + } + } + + html::div -id "portal-subnavigation" { + html::div -id "portal-subnavigation-links" { + html::ul { + html::li { + html::a -href "/dotlrn/?page_num=0" {html::t "Eigene Startseite"} + } + html::li { + html::a -href "/dotlrn/?page_num=1" {html::t "Eigener Kalender"} + } + html::li { + html::a -href "/dotlrn/?page_num=2" {html::t "Eigene Dateien"} + } + } + } + } + + html::div -id "portal" { + set slave [tmpl::div] + } + } + } + html::t "hello footer" + } + return $slave +} +pageMaster set title $title +pageMaster set context [lindex $context 0] + +ns_log notice "render time [time {t1 asHTML -page -master ::pageMaster}]" \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/running.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/running.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/running.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,7 @@ + +@title;noquote@ +@context;noquote@ + +
+@t1;noquote@ +
Index: openacs-4/packages/xotcl-request-monitor/www/running.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/running.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/running.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,75 @@ +ad_page_contract { + Displays last requests of a user + + @author Gustaf Neumann (adapted for interaction with controlling thread) + @cvs-id $Id: running.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} -query { + orderby:optional +} -properties { + title:onevalue + context:onevalue + user_string:onevalue +} + +set admin_p [acs_user::site_wide_admin_p] +if {!$admin_p} { + ad_return_warning "Insufficient Permissions" \ + "Only side wide admins are allowed to view this page!" + ad_script_abort +} + +set running_requests [throttle running] +set background_requests [bgdelivery running] +set nr_bg [expr {[llength $background_requests]/2}] +set nr_req [expr {[llength $running_requests]/2}] +set title "Currently Running Requests ($nr_req/$nr_bg)" +set context [list "Running Requests"] + +TableWidget t1 \ + -actions [subst { + Action new -label Refresh -url [ad_conn url] -tooltip "Reload current page" + }] \ + -columns { + AnchorField user -label "User" + Field url -label "Url" + Field elapsed -label "Elapsed Time" -html { align right } + Field background -label "Background" + } \ + -no_data "Currently no running requests" + +set sortable_requests [list] +foreach {key elapsed} $running_requests { + foreach {requestor url} [split $key ,] break + set ms [format %.2f [expr {[throttle ms -start_time $elapsed]/1000.0}]] + if {[string first . $requestor] > 0} { + set user_string $requestor + } else { + acs_user::get -user_id $requestor -array user + set user_string "$user(first_names) $user(last_name)" + } + set user_url "last-requests?request_key=$requestor" + lappend sortable_requests [list $user_string $user_url $url $ms ""] +} +foreach {index entry} $background_requests { + foreach {key elapsed} $entry break + foreach {requestor url} [split $key ,] break + set ms [format %.2f [expr {[throttle ms -start_time $elapsed]/1000.0}]] + if {[string first . $requestor] > 0} { + set user_string $requestor + } else { + acs_user::get -user_id $requestor -array user + set user_string "$user(first_names) $user(last_name)" + } + set user_url "last-requests?request_key=$requestor" + lappend sortable_requests [list $user_string $user_url $url -$ms "background"] +} + +foreach r [lsort -decreasing -real -index 3 $sortable_requests] { + foreach {user_string user_url url ms mode} $r break + if {$ms<0} {set ms [expr {-$ms}]} + t1 add \ + -user $user_string -user.href $user_url \ + -url $url -elapsed $ms -background $mode +} + +set t1 [t1 asHTML] Index: openacs-4/packages/xotcl-request-monitor/www/stat-details.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/stat-details.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/stat-details.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,11 @@ + +@title;noquote@ +@context;noquote@ + +

@user_string;noquote@

+
+@t1;noquote@ +
+ + + Index: openacs-4/packages/xotcl-request-monitor/www/stat-details.adp-old =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/stat-details.adp-old,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/stat-details.adp-old 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,11 @@ + +@title;noquote@ +@context;noquote@ + +

@user_string;noquote@

+
+ +
+ + + Index: openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,100 @@ +ad_page_contract { + Displays last requests of a user + + @author Gustaf Neumann + + @cvs-id $id: whos-online.tcl,v 1.1.1.1 2004/03/16 16:11:51 nsadmin exp $ +} -query { + {all:optional 0} + {orderby:optional "totaltime,desc"} +} -properties { + title:onevalue + context:onevalue + user_string:onevalue +} + +set title "Url Statistics" +set context [list "Url Statistics"] +set hide_patterns [parameter::get -parameter hide-requests -default {*.css}] + +set stat [throttle report_url_stats] +set total 0.0 +set cnt 0 +set full_stat [list] + +foreach l $stat { + set total [expr {$total+[lindex $l 1]}] + set cnt [expr {$cnt +[lindex $l 2]}] + lappend full_stat [lappend l [expr {[lindex $l 1]/[lindex $l 2]}]] +} +set total_avg [expr {$cnt>0 ? $total/($cnt*1000.0) : "0" }] + +set label(0) "Show filtered" +set tooltip(0) "Show filtered values" +set label(1) "Show all" +set tooltip(1) "Show all values" +set all [expr {!$all}] +set url [export_vars -base [ad_conn url] {all}] + +switch -glob $orderby { + *,desc {set order -decreasing} + *,asc {set order -increasing} +} +switch -glob $orderby { + url,* {set index 0; set type -dictionary} + totaltime,* {set index 1; set type -integer} + cnt,* {set index 2; set type -integer} + avg,* {set index 3; set type -integer} +} + + +TableWidget t1 \ + -actions [subst { + Action new -label "$label($all)" -url $url -tooltip "$tooltip($all)" + Action new -label "Delete Statistics" -url flush-url-statistics \ + -tooltip "Delete URL Statistics" + }] \ + -columns { + Field url -label "Request" -orderby url + Field totaltime -label "Total Time" -html { align right } -orderby totaltime + Field cnt -label "Count" -html { align right } -orderby cnt + Field avg -label "Ms" -html { align right } -orderby avg + Field total -label "Total" -html { align right } + } + + set nr 0 + set hidden 0 + set all [expr {!$all}] + foreach l [lsort $type $order -index $index $full_stat] { + set avg [expr {[lindex $l 1]/[lindex $l 2]}] + set rel [expr {($avg/1000.0)/$total_avg}] + set url [lindex $l 0] + if {!$all} { + set exclude 0 + foreach pattern $hide_patterns { + if {[string match $pattern $url]} { + set exclude 1 + incr hidden + break + } + } + if {$exclude} continue + } + t1 add -url [string_truncate_middle -len 80 $url] \ + -totaltime [lindex $l 1] \ + -cnt [lindex $l 2] \ + -avg $avg \ + -total [format %.2f%% [expr {[lindex $l 1]*100.0/$total}]] + } + +set t1 [t1 asHTML] + +append user_string "Grand Total Avg Response time: " \ + [format %6.2f $total_avg] " seconds/call " \ + "(base: $cnt requests)
" + +append user_string "$hidden requests hidden." +if {$hidden>0} { + append user_string " (Patterns: $hide_patterns)" +} + Index: openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl-old =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl-old,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/stat-details.tcl-old 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,149 @@ +ad_page_contract { + Displays last requests of a user + + @author Gustaf Neumann + + @cvs-id $id: whos-online.tcl,v 1.1.1.1 2004/03/16 16:11:51 nsadmin exp $ +} -query { + {all:optional 0} + {orderby:optional "totaltime,desc"} +} -properties { + title:onevalue + context:onevalue + user_string:onevalue +} + +set title "Url Statistics" +set context [list "Url Statistics"] +set hide_patterns [parameter::get -parameter hide-requests -default {*.css}] + +set stat [throttle report_url_stats] +set total 0.0 +set cnt 0 +set full_stat [list] + +foreach l $stat { + set total [expr {$total+[lindex $l 1]}] + set cnt [expr {$cnt +[lindex $l 2]}] + lappend full_stat [lappend l [expr {[lindex $l 1]/[lindex $l 2]}]] +} +set total_avg [expr {$cnt>0 ? $total/($cnt*1000.0) : "0" }] + +set label(0) "Show filtered" +set tooltip(0) "Show filtered values" +set label(1) "Show all" +set tooltip(1) "Show all values" +set all [expr {!$all}] +set url [export_vars -base [ad_conn url] {all}] + +template::list::create \ + -name stat_details \ + -actions [list $label($all) $url $tooltip($all) \ + "Delete Statistics" flush-url-statistics "Delete URL Statistics"] \ + -elements { + url { + label "Request" + orderby url + } + totaltime { + label "Total Time" + html { align right } + aggregate sum + orderby totaltime + } + cnt { + label "Count" + html { align right } + aggregate sum + orderby cnt + } + avg { + label "Ms" + html { align right } + orderby avg + } + total { + label "Total" + html { align right } + } + } +set all [expr {!$all}] + +multirow create stat_details url totaltime cnt avg total +set hidden 0 + +switch -glob $orderby { + *,desc {set order -decreasing} + *,asc {set order -increasing} +} +switch -glob $orderby { + url,* {set index 0; set type -dictionary} + totaltime,* {set index 1; set type -integer} + cnt,* {set index 2; set type -integer} + avg,* {set index 3; set type -integer} +} + +foreach l [lsort $type $order -index $index $full_stat] { + set avg [expr {[lindex $l 1]/[lindex $l 2]}] + set rel [expr {($avg/1000.0)/$total_avg}] + + set url [lindex $l 0] + if {!$all} { + set exclude 0 + foreach pattern $hide_patterns { + if {[string match $pattern $url]} { + set exclude 1 + incr hidden + break + } + } + if {$exclude} continue + } + multirow append stat_details \ + [string_truncate_middle -len 100 $url] [lindex $l 1] [lindex $l 2] \ + $avg [format %.2f%% [expr {[lindex $l 1]*100.0/$total}]] +} + +#array set color { +# red {
} +# orange {
} +# yellow {
} +# green {
} +# ok {} +#} + +#set fmt "%-75s|%14d|%7d|%10.0f|%8.2f%%\n" +#set fmtn "%-75s|%14s|%7s|%10s|%9s
" +set report "
"
+#append report [format $fmtn "" total cnt avg percent]
+
+#foreach l [lsort -real -decreasing -index 1 $stat] {
+#  set avg [expr {[lindex $l 1]/[lindex $l 2]}]
+#  set rel [expr {($avg/1000.0)/$total_avg}]
+#  if {$rel > 3} {set code red} \
+#  elseif {$rel > 2} {set code orange} \
+#  elseif {$rel > 1} {set code yellow} \
+#  elseif {$rel < 0.5} {set code green} \
+#  else {set code ok}
+#  if {[string compare $color($code) ""]} {
+#    set endtag 
+# } else { +# set endtag "" +# } +# append report $color($code) [format $fmt \ +# [lindex $l 0] [lindex $l 1] [lindex $l 2] \ +# $avg \ +# [expr {[lindex $l 1]*100.0/$total}] \ +# ] $endtag +#} +append user_string "Grand Total Avg Response time: " \ + [format %6.2f $total_avg] " seconds/call " \ + "(base: $cnt requests)
" + +append user_string "$hidden requests hidden." +if {$hidden>0} { + append user_string " (Patterns: $hide_patterns)" +} + + + Index: openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,10 @@ + +@title@ + +
@throttle_statistics;noquote@
+ +

Throttle UrlStats

+
+ +
+ Index: openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/throttle-statistics.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,45 @@ +ad_page_contract { + present throttle statistics, active users, etc + + @author Gustaf Neumann + @cvs-id $Id: throttle-statistics.tcl,v 1.1 2005/12/14 16:09:02 maltes Exp $ +} -properties { + title:onevalue + context:onevalue + throttle_statistics + throttle_url_statistics +} + +set title "Throttle statistics" +set throttle_statistics [throttle statistics] +set data [throttle url_statistics] + +template::list::create \ + -name url_statistics \ + -elements { + time {label Time} + type {label Type} + user { + label Userid + link_url_col user_url} + IPadress {label "IP Address"} + URL {label "URL"} + } + +multirow create url_statistics type user user_url time IPadress URL +foreach l [lsort -index 2 $data] { + foreach {type user time IPadress URL} $l break + if {[string match *.* $user]} { + set user "Anonymous" + set user_url "" + } else { + acs_user::get -user_id $user -array userinfo + set user_url /acs-admin/users/one?user_id=$user + set user "$userinfo(first_names) $userinfo(last_name)" + } + set time [clock format $time -format "%Y-%m-%d %H:%M:%S"] + multirow append url_statistics $type $user $user_url $time $IPadress $URL +} + +#set throttle_url_statistics [throttle url_statistics] + Index: openacs-4/packages/xotcl-request-monitor/www/users-in-community.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/users-in-community.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/users-in-community.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,5 @@ + +@title;noquote@ +@context;noquote@ + +@t1;noquote@ Index: openacs-4/packages/xotcl-request-monitor/www/users-in-community.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/users-in-community.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/users-in-community.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,40 @@ +ad_page_contract { + Displays active users in a community + + @author Gustaf Neumann + + @cvs-id $id$ +} -query { + community_id +} -properties { + title:onevalue + context:onevalue +} + +set community_name [dotlrn_community::get_community_name $community_id] +set title "Users in Community $community_name" +set context [list $title] +set stat [list] + +TableWidget t1 \ + -columns { + Field time -label "Last Activity" -html {align center} + Field user -label User + } + +foreach e [lsort -decreasing -index 0 \ + [throttle users in_community $community_id]] { + foreach {timestamp requestor} $e break + if {[info exists listed($requestor)]} continue + set listed($requestor) 1 + if {[string first . $requestor] > 0} { + set user_string $requestor + } else { + acs_user::get -user_id $requestor -array user + set user_string "$user(first_names) $user(last_name)" + } + set time [clock format $timestamp -format "%H:%M"] + t1 add -time $time -user $user_string +} + +set t1 [t1 asHTML] Index: openacs-4/packages/xotcl-request-monitor/www/whos-online.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/whos-online.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/whos-online.adp 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,9 @@ + +@title;noquote@ +@context;noquote@ + +

@summarize_categories@ + +

+@t1;noquote@ +
Index: openacs-4/packages/xotcl-request-monitor/www/whos-online.adp-old =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/whos-online.adp-old,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/whos-online.adp-old 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,6 @@ + +@title;noquote@ +@context;noquote@ + +

@summarize_categories@ +

Index: openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,149 @@ +ad_page_contract { + Displays who's currently online + + @author Gustaf Neumann (adapted for interaction with controlling thread) + + @cvs-id $id: whos-online.tcl,v 1.1.1.1 2004/03/16 16:11:51 nsadmin exp $ +} -query { + {orderby:optional "name,asc"} + {all:optional 1} +} -properties { + title:onevalue + context:onevalue +} + +set title "Who's online?" +set context [list "Who's online"] + +# get value from package parameters +set peer_groups [parameter::get -parameter peer-groups \ + -default {*wlan* *dsl* *.com *.net *.org}] + +set admin [acs_user::site_wide_admin_p] +#set admin 0 + +set label(0) "Authenticated only" +set tooltip(0) "Show authenticated users only" +set label(1) all +set tooltip(1) "Show all users" +set all [expr {!$all}] +set url [export_vars -base [ad_conn url] {request_key all}] + +TableWidget t1 \ + -actions [subst { + Action new -label "$label($all)" -url $url -tooltip "$tooltip($all)" + Action new -label "Delete Statistics" -url flush-url-statistics \ + -tooltip "Delete URL Statistics" + }] \ + -columns [subst { + AnchorField name -label "User" -orderby name + Field online_time -label "Last Activity" -html { align right } \ + -orderby online_time + if {$admin} { + Field activity -label "Activity" -html { align right } -orderby activity + AnchorField hits -label "Hits" -orderby hits + Field switches -label "Switches" -html { align center } -orderby switches + Field peer_address -label "Peer" -orderby peer_address + } + }] \ + -no_data "no registered users online" + + +foreach cat $peer_groups {set peer_cat_count($cat) 0} +set peer_cat_count(others) 0 + +# this proc is used only for caching purposes +proc my_hostname pa { + if {[catch {set peer [ns_hostbyaddr $pa]}]} { return $pa } + return "$peer ($pa)" + #return "$peer" +} + +set users [list] +foreach element [throttle users active -full] { + foreach {user_id pa timestamp hits smooth switches} $element break + if {[string first . $user_id] > 0} { + if {$all} continue + # it was an IP address + set user_label $user_id + set user_url "" + } else { + acs_user::get -user_id $user_id -array user + set user_label "$user(last_name), $user(first_names)" + set user_url [acs_community_member_url -user_id $user_id] + } + set timestamp [lindex $smooth 2] + set last_request_minutes [expr {[clock seconds]/60 - $timestamp}] + + set peer $pa + if {$admin} { + catch {set peer [util_memoize [string tolower \ + [list ::template::my_hostname $pa]]]} + set match 0 + foreach cat $peer_groups { + if {[string match $cat $peer]} { + incr peer_cat_count($cat) + set match 1 + break + } + } + if {!$match} { + incr peer_cat_count(others) + append peer " ???" + } + } + set loadparam "1m=[lindex $smooth 3], 10m=$hits" + set detail_url "last-requests?request_key=$user_id" + + lappend users [list $user_label \ + $user_url \ + $last_request_minutes "$last_request_minutes minutes ago" \ + [format %.2f [lindex $smooth 0]] \ + $hits $loadparam $detail_url \ + $switches \ + $peer] +} + +switch -glob $orderby { + *,desc {set order -decreasing} + *,asc {set order -increasing} +} +switch -glob $orderby { + name,* {set index 0; set type -dictionary} + online_time,* {set index 2; set type -integer} + activity,* {set index 4; set type -real} + hits,* {set index 5; set type -dictionary} + switches,* {set index 8; set type -integer} + peer_address,* {set index 9; set type -dictionary} +} + +if {$admin} { + set total $peer_cat_count(others) + foreach cat $peer_groups {incr total $peer_cat_count($cat)} + set summarize_categories "$total users logged in from: " + foreach cat $peer_groups { + append summarize_categories "$cat [format %.2f [expr {$peer_cat_count($cat)*100.0/$total}]]%, " + } + append summarize_categories "others [format %.2f [expr {$peer_cat_count(others)*100.0/$total}]]%. " +} else { + set summarize_categories "" +} + +foreach e [lsort $type $order -index $index $users] { + if {$admin} { + t1 add -name [lindex $e 0] \ + -name.href [lindex $e 1] \ + -online_time [lindex $e 4] \ + -activity [lindex $e 5] \ + -hits [lindex $e 6] \ + -hits.href [lindex $e 7] \ + -switches [lindex $e 8] \ + -peer_address [lindex $e 9] + } else { + t1 add -name [lindex $e 0] \ + -name.href [lindex $e 1] \ + -online_time [lindex $e 4] + } +} + +set t1 [t1 asHTML] Index: openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl-old =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl-old,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/whos-online.tcl-old 14 Dec 2005 16:09:02 -0000 1.1 @@ -0,0 +1,170 @@ +ad_page_contract { + Displays who's currently online + + @author Peter Marklund + @author Gustaf Neumann (adapted for interaction with controlling thread) + + @cvs-id $id: whos-online.tcl,v 1.1.1.1 2004/03/16 16:11:51 nsadmin exp $ +} -query { + {orderby:optional "name,asc"} + {all:optional 1} +} -properties { + title:onevalue + context:onevalue +} + +set title "Who's online?" +set context [list "Who's online"] + +# get value from package parameters +set peer_groups [parameter::get -parameter peer-groups \ + -default {*wlan* *dsl* *.com *.net *.org}] + +set admin [acs_user::site_wide_admin_p] +#set admin 0 +set template_elements { + name { + label "User" + link_url_col url + orderby name + } + online_time { + label "Last Activity" + html { align right } + orderby online_time + } +} + +if {$admin} { + append template_elements { + activity { + label "Activity" + html { align right } + orderby activity + } + hits { + label "Hits" + link_url_col detail_url + orderby hits + } + switches { + label "Switches" + html { align center } + orderby switches + } + peer_address { + label "Peer" + orderby peer_address + } + } + foreach cat $peer_groups {set peer_cat_count($cat) 0} + set peer_cat_count(others) 0 +} + +# this proc is used only for caching purposes +proc my_hostname pa { + if {[catch {set peer [ns_hostbyaddr $pa]}]} { return $pa } + return "$peer ($pa)" + #return "$peer" +} + +set label(0) "Authenticated only" +set tooltip(0) "Show authenticated users only" +set label(1) all +set tooltip(1) "Show all users" +set all [expr {!$all}] +set url [export_vars -base [ad_conn url] {request_key all}] + +template::list::create \ + -actions [list $label($all) $url $tooltip($all)] \ + -name online_users \ + -no_data "no registered users online" \ + -elements $template_elements + +set users [list] +foreach element [throttle users active -full] { + foreach {user_id pa timestamp hits smooth switches} $element break + if {[string first . $user_id] > 0} { + if {$all} continue + # it was an IP address + set user_label $user_id + set user_url "" + #continue + } else { + acs_user::get -user_id $user_id -array user + set user_label "$user(last_name), $user(first_names)" + set user_url [acs_community_member_url -user_id $user_id] + + } + set timestamp [lindex $smooth 2] + set last_request_minutes [expr {[clock seconds]/60 - $timestamp}] + + set peer $pa + if {$admin} { + catch {set peer [util_memoize [string tolower \ + [list ::template::my_hostname $pa]]]} + set match 0 + foreach cat $peer_groups { + if {[string match $cat $peer]} { + incr peer_cat_count($cat) + set match 1 + break + } + } + if {!$match} { + incr peer_cat_count(others) + append peer " ???" + } + } + set loadparam "1m=[lindex $smooth 3], 10m=$hits" + set detail_url "last-requests?request_key=$user_id" + + lappend users [list $user_label \ + $user_url \ + $last_request_minutes "$last_request_minutes minutes ago" \ + [format %.2f [lindex $smooth 0]] \ + $hits $loadparam $detail_url \ + $switches \ + $peer] +} + +switch -glob $orderby { + *,desc {set order -decreasing} + *,asc {set order -increasing} +} +switch -glob $orderby { + name,* {set index 0; set type -dictionary} + online_time,* {set index 2; set type -integer} + activity,* {set index 4; set type -real} + hits,* {set index 5; set type -dictionary} + switches,* {set index 8; set type -integer} + peer_address,* {set index 9; set type -dictionary} +} + +if {$admin} { + multirow create online_users name url online_time \ + activity hits detail_url switches peer_address + set total $peer_cat_count(others) + foreach cat $peer_groups {incr total $peer_cat_count($cat)} + set summarize_categories "$total users logged in from: " + foreach cat $peer_groups { + append summarize_categories "$cat [format %.2f [expr {$peer_cat_count($cat)*100.0/$total}]]%, " + } + append summarize_categories "others [format %.2f [expr {$peer_cat_count(others)*100.0/$total}]]%. " +} else { + set summarize_categories "" + multirow create online_users name url online_time +} + +foreach e [lsort $type $order -index $index $users] { + multirow append online_users \ + [lindex $e 0] \ + [lindex $e 1] \ + [lindex $e 3] \ + [lindex $e 4] \ + [lindex $e 6] \ + [lindex $e 7] \ + [lindex $e 8] \ + [lindex $e 9] \ +} + Index: openacs-4/packages/xotcl-request-monitor/www/resources/backcolor.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/backcolor.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/area_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/area_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/area_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,83 @@ + + + +JavaScript Diagram Builder - The Area object + + + + + +
+
+

JavaScript Diagram Builder - The Area object

+
+The Area object is used to display an area chart into the diagram. You can also hide, move and delete it +after it has been drawn. In order to draw the area object you need the images o_rrggbb.gif, d_rrggbb.gif, +p_rrggbb.gif, q_rrggbb.gif and b_rrggbb.gif, which must be in the same directory. Red, blue and black +images are already available. If you want to use other colors, you must first generate the required images. +
+ + +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 520, 360);
+D.SetBorder(Date.UTC(2000,11,15,0,0,0), Date.UTC(2001,11,15,0,0,0), -300, 1100);
+D.SetText("","", "profit/loss per day during the last year");
+D.XScale=4;
+D.YScale=" $";
+D.Draw("#FFFFCC", "#000000", false);
+var i, t0, t1, P0, P1, base=D.ScreenY(0);
+t1=D.ScreenX(Date.UTC(2000,11,15,0,0,0));
+P1=0;
+for (i=0; i<12; i++)
+{ t0=t1; P0=P1;
+  t1=D.ScreenX(Date.UTC(2001,i,15,0,0,0));
+  P1+=(i/5-Math.random())*100;
+  new Area(t0, D.ScreenY(P0), t1, D.ScreenY(P1), "ff0000", base, "profit/loss per day");
+}
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var A = new Area(theX0, theY0, theX1, theY1, theColor, theBase[, theTooltipText[,
    +theOnClickAction[, theOnMouseoverAction[, theOnMouseoutAction]]]])

    +//Constructor and Display, requires images o_*, d_*, p_* q_* and b_* (*=theColor+".gif")
  • +
  • A.SetColor(theColor) //Color
  • +
  • A.SetVisibility(isVisible) //Show or Hide
  • +
  • A.SetTitle(theTitle) //TooltipText
  • +
  • A.MoveTo(theLeft, theTop) //Move
  • +
  • A.ResizeTo(theX0, theY0, theX1, theY1) //Resize
  • +
  • A.Delete() //Delete DIV object of A from the document
  • +
  • delete A //Destructor
  • +

+
+ + + +
« The Line objectThe Arrow object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/arrow_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/arrow_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/arrow_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,71 @@ + + + +JavaScript Diagram Builder - The Arrow object + + + + + +
+
+

JavaScript Diagram Builder - The Arrow object

+
+The Arrow object is used to display an arrow on the screen, especially to draw it in a diagram area. It is +possible to hide, move and delete an arrow after it has been drawn. The Arrow object has a quite large +invisible border, so that it can interfere with the TooltipText and onClick event of neighbouring objects. +Because of that you should always draw the Arrow objects first, before drawing any neighbouring Bar or Box objects. +
+ + +
+This arrows were generated by

+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(60, 140, 300, 380);
+D.SetBorder(-1, 1, -1, 1);
+var i, x, y;
+for (i=0; i<11; i++)
+{ x=Math.sin((i+0.5)*2*Math.PI/11);
+  y=Math.cos((i+0.5)*2*Math.PI/11);
+  new Arrow(D.ScreenX(x/3), D.ScreenY(y/3), D.ScreenX(x), D.ScreenY(y), "#0000ff", i%5+1);
+}
+document.close();
+</SCRIPT> +
+
+

+You can use the following methods: +
    +
  • var A = new Arrow(theX0, theY0, theX1, theY1, theColor[, theSize[, theTooltipText[,
    +theOnClickAction[, theOnMouseoverAction[, theOnMouseoutAction]]]]])
    +//Constructor and Display
  • +
  • A.SetColor(theColor) //Color
  • +
  • A.SetVisibility(isVisible) //Show or Hide
  • +
  • A.SetTitle(theTitle) //TooltipText
  • +
  • A.MoveTo(theLeft, theTop) //Move
  • +
  • A.ResizeTo(theX0, theY0, theX1, theY1) //Resize
  • +
  • A.Delete() //Delete DIV object of A from the document
  • +
  • delete A //Destructor
  • +

+
+ + + +
« The Area objectThe Pie object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_000000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_000000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_0000ff.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_0000ff.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_ff0000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/b_ff0000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/bar_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/bar_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/bar_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,87 @@ + + + +JavaScript Diagram Builder - The Bar object + + + + + +
+
+

JavaScript Diagram Builder - The Bar object

+
+The Bar object is used to display a bar on the screen, especially to draw it in a diagram area. In order to +find the appropriate screen position and size of the bar, the diagram functions ScreenX, ScreenY, RealX and +RealY can be used. It is also possible, to move, resize, hide and delete a bar after it has been drawn. +
+ + +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 520, 360);
+D.SetBorder(-1, 13, 0, 1000);
+D.SetText("","", "Website Hits 2001");
+D.XScale=0;
+D.Draw("#FFFF80", "#004080", false);
+var i, j, y;
+Month=new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+for (i=0; i<12; i++)
+{ y=500+Math.random()*400;
+  j=D.ScreenX(i+0.5);
+  if (i%2==0) new Bar(j-15, D.ScreenY(y), j+15, D.ScreenY(0), "#0000FF", Month[i], "#FFFFFF", "Hits per month");
+  else new Bar(j-15, D.ScreenY(y), j+15, D.ScreenY(0), "#FF0000", Month[i], "#000000", "Hits per month");
+}
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var B = new Bar(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor
    +[, theTooltipText[, theOnClickAction[, theOnMouseoverAction[, theOnMouseoutAction]]]])

    +//Constructor and Display, if theText="" then min_height=1 else min_height=12
    +//if you want to use B.SetText() later, then you must initialize with a Text<>""
  • +
  • B.SetColor(theColor) //Color
  • +
  • B.SetVisibility(isVisible) //Show or Hide
  • +
  • B.SetText(theText) //Text or Image
  • +
  • B.SetTitle(theTitle) //TooltipText
  • +
  • B.MoveTo(theLeft, theTop) //Move
  • +
  • B.ResizeTo(theLeft, theTop, theWidth, theHeight) //Resize
  • +
  • B.Delete() //Delete DIV object of B from the document
  • +
  • delete B //Destructor
  • +
+Before drawing, you can change the text style: +
+_BFont=theFont;
+_BFont is a global variable, which is valid for all Bar and Box objects. +The default setting is
+_BFont="font-family:Verdana;font-weight:bold;font-size:10pt;line-height:13pt;". +

+
+ + + +
« The Diagram objectThe Box object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/blank.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/blank.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/blank.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/box_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/box_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/box_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,85 @@ + + + +JavaScript Diagram Builder - The Box object + + + + + +
+
+

JavaScript Diagram Builder - The Box object

+
+The Box object is similar to the bar object. It has 2 additional properties: BorderWidth and BorderColor. +Bar and box objects can also be used with an image-tag instead of the text. In this way you can display +the objects also in 3D look. For transparent objects (this diagram) use the background color "". +
+ + +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 520, 360);
+D.SetBorder(Date.UTC(2000,11,15,0,0,0), Date.UTC(2001,11,15,0,0,0), 0, 1000);
+D.SetText("","", "Website Hits 2001");
+D.XScale=4;
+D.Draw("", "#004080", false);
+var i, j, y, y0=D.ScreenY(0);
+for (i=0; i<12; i++)
+{ y=D.ScreenY(500+Math.random()*400);
+  j=D.ScreenX(Date.UTC(2001,i,1,0,0,0));
+  if (i%2==0) new Box(j-12, y, j+12, y0, "#0000FF", "v_blue.gif", "#FFFFFF", 1, "#000000");
+  else new Box(j-12, y, j+12, y0, "#FF0000", "v_red.gif", "#000000", 1, "#000000");
+}
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var B = new Box(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor
    +[, theBorderWidth[, theBorderColor[, theTooltipText[, theOnClickAction[,
    theOnMouseoverAction[, theOnMouseoutAction]]]]]])

    +//Constructor and Display, if theText="" then min_height=1 else min_height=12
    +//if you want to use B.SetText() later, then you must initialize with a Text<>""
  • +
  • B.SetColor(theColor) //Color
  • +
  • B.SetVisibility(isVisible) //Show or Hide
  • +
  • B.SetText(theText) //Text or Image
  • +
  • B.SetTitle(theTitle) //TooltipText
  • +
  • B.MoveTo(theLeft, theTop) //Move
  • +
  • B.ResizeTo(theLeft, theTop, theWidth, theHeight) //Resize
  • +
  • B.Delete() //Delete DIV object of B from the document
  • +
  • delete B //Destructor
  • +
+Before drawing, you can change the text style: +
+_BFont=theFont;
+_BFont is a global variable, which is valid for all Bar and Box objects. +The default setting is
+_BFont="font-family:Verdana;font-weight:bold;font-size:10pt;line-height:13pt;". +

+
+ + + +
« The Bar objectThe Dot object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/browser_support.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/browser_support.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/browser_support.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,233 @@ + + + + + + +JavaScript Diagram Builder - Browser support + + + + + +
+
+

JavaScript Diagram Builder - Browser support

+
+The JavaScript Diagram Builder works with Microsoft Internet Explorer 4.x, Netscape 4.x, Netscape 6.x and Opera 5.x +under Windows and with Netscape 6.x, Opera 5.x and Konqueror 3.x under Linux. Most of the methods, which dynamically change +the properties of the objects, will only work correctly with IE 5, Netscape 6, Opera 7 and Konqueror 3 or higher. +Here you can test the methods for the single objects. +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method\ObjectDiagramBarBoxDotPixelLineAreaArrowPie
Draw/SetColor
SetVisibility
SetText      
SetTitle 
MoveTo 
ResizeTo   
Delete
+
+
+
+Because of a bug in Netscape 4.x (N4) you should add the following code in the web page
+before using the diagram objects:
+<DIV STYLE="position:absolute; top:0px"></DIV>
+Also for N4 the file transparent.gif must be in the directory of the web page.
+Furthermore, N4 has trouble when opening a page with a diagram in a new window, because the extern script will not be +included. In order to work around this bug, you must reload the page, it also can be done automatically with
+<SCRIPT Language="JavaScript">if ((document.layers)&&(history.length==1)) location.href=location.href+"#";</SCRIPT> +
which must be written in the head before including the extern script.
+Tooltiptext will not work at all with N4. Click on a Bar or Box works only with N4, if you click on the text.
+
+In order to print all objects correctly, you must specify in your browser settings to print also the background. +For instance in Internet Explorer, use the menu View->Internet Options->Advanced and enable "Print backgrounds colors and images".
+
+Since version 2.8 the formerly script file diagram.js is splitted into the 3 files diagram.js (13 kB - browser independent code), +diagram_nav.js (98 kb - code for Netscape 4) and diagram_dom.js (89 kB - code for browsers which are DOM conform). +In this way the total file size for the download decreases, because the new file diagram.js automatically loads - depending on the detected browser +- only one of the files diagram_nav.js or diagram_dom.js. This makes also the execution of the script a bit faster, because +browser dependent overhead within the methods of the objects is no longer required.
+If you do not use Line, Area, Arrow or Pie objects, then you can significantly reduce the file size by deleting the appropriate code from the script file.
+If the script files diagram*.js are not in the same directory as the html page which uses the script, then you must edit +the file diagram.js and set the correct relative or absolute path in the variable _PathToScript.
+
+The last remark is about names of variables, functions and IDs: The Diagram Builder uses some global variables and functions, +all of them start with the letter "_" (for instance "_Draw()"). In order to prevent bugs caused by duplicate names of +variables or functions, you should not use names which begin with the letter "_" in your script. Additionally, there are +IDs for the objects, which start with "Dia", "Bar", "Box", "Dot", "Pix", "Line", "Area", "Arrow" or "Pie". Don't use ID's in your HTML page, +which start with this letters (for instance don't use <div id='Dia1'>...</div>). +
+
+ + + +
« Logarithmic Scale ExamplePHP & ASP »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_000000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_000000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_0000ff.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_0000ff.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_ff0000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/d_ff0000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram.js 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,389 @@ +// JavaScript Diagram Builder 3.31 +// Copyright (c) 2001-2005 Lutz Tautenhahn, all rights reserved. +// +// The Author grants you a non-exclusive, royalty free, license to use, +// modify and redistribute this software, provided that this copyright notice +// and license appear on all copies of the software. +// This software is provided "as is", without a warranty of any kind. + +var _N_Dia=0, _N_Bar=0, _N_Box=0, _N_Dot=0, _N_Pix=0, _N_Line=0, _N_Area=0, _N_Arrow=0, _N_Pie=0, _zIndex=0; +var _dSize = (navigator.appName == "Microsoft Internet Explorer") ? 1 : -1; +if (navigator.userAgent.search("Opera")>=0) _dSize=-1; +var _IE=0; +if (_dSize==1) +{ _IE=1; + if (window.document.documentElement.clientHeight) _dSize=-1; //IE in standards-compliant mode +} +var _nav4 = (document.layers) ? 1 : 0; +var _DiagramTarget=window; +var _BFont="font-family:Verdana;font-weight:bold;font-size:10pt;line-height:13pt;" +var _PathToScript="/resources/xotcl-request-monitor/diagram/"; +if (document.layers) document.write(""); +else document.write(""); + +function Diagram() +{ this.xtext=""; + this.ytext=""; + this.title=""; + this.XScale=1; + this.YScale=1; + this.XScalePosition="bottom"; + this.YScalePosition="left"; + this.Font="font-family:Verdana;font-weight:normal;font-size:10pt;line-height:13pt;"; + this.ID="Dia"+_N_Dia; _N_Dia++; _zIndex++; + this.zIndex=_zIndex; + this.logsub=new Array(0.301, 0.477, 0.602, 0.699, 0.778, 0.845, 0.903, 0.954); + this.SetFrame=_SetFrame; + this.SetBorder=_SetBorder; + this.SetText=_SetText; + this.SetGridColor=_SetGridColor; + this.SetXGridColor=_SetXGridColor; + this.SetYGridColor=_SetYGridColor; + this.ScreenX=_ScreenX; + this.ScreenY=_ScreenY; + this.RealX=_RealX; + this.RealY=_RealY; + this.XGrid=new Array(3); + this.GetXGrid=_GetXGrid; + this.YGrid=new Array(3); + this.GetYGrid=_GetYGrid; + this.XGridDelta=0; + this.YGridDelta=0; + this.XSubGrids=0; + this.YSubGrids=0; + this.SubGrids=0; + this.XGridColor=""; + this.YGridColor=""; + this.XSubGridColor=""; + this.YSubGridColor=""; + this.MaxGrids=0; + this.DateInterval=_DateInterval; + this.Draw=_Draw; + this.SetVisibility=_SetVisibility; + this.SetTitle=_SetTitle; + this.Delete=_Delete; + return(this); +} +function _SetFrame(theLeft, theTop, theRight, theBottom) +{ this.left = theLeft; + this.right = theRight; + this.top = theTop; + this.bottom = theBottom; +} +function _SetBorder(theLeftX, theRightX, theBottomY, theTopY) +{ this.xmin = theLeftX; + this.xmax = theRightX; + this.ymin = theBottomY; + this.ymax = theTopY; +} +function _SetText(theScaleX, theScaleY, theTitle) +{ this.xtext=theScaleX; + this.ytext=theScaleY; + this.title=theTitle; +} +function _SetGridColor(theGridColor, theSubGridColor) +{ this.XGridColor=theGridColor; + this.YGridColor=theGridColor; + if ((theSubGridColor)||(theSubGridColor=="")) + { this.XSubGridColor=theSubGridColor; + this.YSubGridColor=theSubGridColor; + } +} +function _SetXGridColor(theGridColor, theSubGridColor) +{ this.XGridColor=theGridColor; + if ((theSubGridColor)||(theSubGridColor=="")) + this.XSubGridColor=theSubGridColor; +} +function _SetYGridColor(theGridColor, theSubGridColor) +{ this.YGridColor=theGridColor; + if ((theSubGridColor)||(theSubGridColor=="")) + this.YSubGridColor=theSubGridColor; +} +function _ScreenX(theRealX) +{ return(Math.round((theRealX-this.xmin)/(this.xmax-this.xmin)*(this.right-this.left)+this.left)); +} +function _ScreenY(theRealY) +{ return(Math.round((this.ymax-theRealY)/(this.ymax-this.ymin)*(this.bottom-this.top)+this.top)); +} +function _RealX(theScreenX) +{ return(this.xmin+(this.xmax-this.xmin)*(theScreenX-this.left)/(this.right-this.left)); +} +function _RealY(theScreenY) +{ return(this.ymax-(this.ymax-this.ymin)*(theScreenY-this.top)/(this.bottom-this.top)); +} +function _sign(rr) +{ if (rr<0) return(-1); else return(1); +} +function _DateInterval(vv) +{ var bb=140*24*60*60*1000; //140 days + this.SubGrids=4; + if (vv>=bb) //140 days < 5 months + { bb=8766*60*60*1000;//1 year + if (vv=bb) { this.SubGrids=7; return(bb/5); } //14 days + bb/=2; //35 days + if (vv>=bb) { this.SubGrids=7; return(bb/5); } //7 days + bb/=7; bb*=4; //20 days + if (vv>=bb) return(bb/5); //4 days + bb/=2; //10 days + if (vv>=bb) return(bb/5); //2 days + bb/=2; //5 days + if (vv>=bb) return(bb/5); //1 day + bb/=2; //2.5 days + if (vv>=bb) return(bb/5); //12 hours + bb*=3; bb/=5; //1.5 day + if (vv>=bb) { this.SubGrids=6; return(bb/6); } //6 hours + bb/=2; //18 hours + if (vv>=bb) { this.SubGrids=6; return(bb/6); } //3 hours + bb*=2; bb/=3; //12 hours + if (vv>=bb) return(bb/6); //2 hours + bb/=2; //6 hours + if (vv>=bb) return(bb/6); //1 hour + bb/=2; //3 hours + if (vv>=bb) { this.SubGrids=6; return(bb/6); } //30 mins + bb/=2; //1.5 hours + if (vv>=bb) { this.SubGrids=5; return(bb/6); } //15 mins + bb*=2; bb/=3; //1 hour + if (vv>=bb) { this.SubGrids=5; return(bb/6); } //10 mins + bb/=3; //20 mins + if (vv>=bb) { this.SubGrids=5; return(bb/4); } //5 mins + bb/=2; //10 mins + if (vv>=bb) return(bb/5); //2 mins + bb/=2; //5 mins + if (vv>=bb) return(bb/5); //1 min + bb*=3; bb/=2; //3 mins + if (vv>=bb) { this.SubGrids=6; return(bb/6); } //30 secs + bb/=2; //1.5 mins + if (vv>=bb) { this.SubGrids=5; return(bb/6); } //15 secs + bb*=2; bb/=3; //1 min + if (vv>=bb) { this.SubGrids=5; return(bb/6); } //10 secs + bb/=3; //20 secs + if (vv>=bb) { this.SubGrids=5; return(bb/4); } //5 secs + bb/=2; //10 secs + if (vv>=bb) return(bb/5); //2 secs + return(bb/10); //1 sec +} +function _DayOfYear(dd,mm,yy) //Unused, you can use this for your own date format +{ DOM=new Array(31,28,31,30,31,30,31,31,30,31,30,31); + var ii, nn=dd; + for (ii=0; ii2)&&(yy%4==0)) nn++; + return(nn); +} +function _GetKWT(dd,mm,yy) //Unused, you can use this for your own date format +{ //this is the implementation of DIN 1355, not of the american standard! + var ss=new Date(yy,0,1); + var ww=ss.getDay(); //0=Sun,1=Mon,2=Tue,3=Wed,4=Thu,5=Fri,6=Sat + ww=(ww+2)%7-3; //0=Mon,1=Tue,2=Wed,3=Thu,-3=Fri,-2=Sat,-1=Sun + ww+=(_DayOfYear(dd,mm,yy)-1); + if (ww<0) return(_GetKWT(24+dd,12,yy-1)); + if ((mm==12)&&(dd>28)) + { if (ww%7+29<=dd) return("01/"+eval(ww%7+1)); //31: Mon-Wed, 30: Mon-Tue, 29: Mon + } + ss=Math.floor(ww/7+1); + if (ss<10) ss="0"+ss; + return(ss+"/"+eval(ww%7+1)); +} +function _DateFormat(vv, ii, ttype) +{ var yy, mm, dd, hh, nn, ss, vv_date=new Date(vv); + Month=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"); + Weekday=new Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat"); + if (ii>15*24*60*60*1000) + { if (ii<365*24*60*60*1000) + { vv_date.setTime(vv+15*24*60*60*1000); + yy=vv_date.getUTCFullYear()%100; + if (yy<10) yy="0"+yy; + mm=vv_date.getUTCMonth()+1; + if (ttype==5) ;//You can add your own date format here + if (ttype==4) return(Month[mm-1]); + if (ttype==3) return(Month[mm-1]+" "+yy); + return(mm+"/"+yy); + } + vv_date.setTime(vv+183*24*60*60*1000); + yy=vv_date.getUTCFullYear(); + return(yy); + } + vv_date.setTime(vv); + yy=vv_date.getUTCFullYear(); + mm=vv_date.getUTCMonth()+1; + dd=vv_date.getUTCDate(); + ww=vv_date.getUTCDay(); + hh=vv_date.getUTCHours(); + nn=vv_date.getUTCMinutes(); + ss=vv_date.getUTCSeconds(); + if (ii>=86400000)//1 day + { if (ttype==5) ;//You can add your own date format here + if (ttype==4) return(Weekday[ww]); + if (ttype==3) return(mm+"/"+dd); + return(dd+"."+mm+"."); + } + if (ii>=21600000)//6 hours + { if (hh==0) + { if (ttype==5) ;//You can add your own date format here + if (ttype==4) return(Weekday[ww]); + if (ttype==3) return(mm+"/"+dd); + return(dd+"."+mm+"."); + } + else + { if (ttype==5) ;//You can add your own date format here + if (ttype==4) return((hh<=12) ? hh+"am" : hh%12+"pm"); + if (ttype==3) return((hh<=12) ? hh+"am" : hh%12+"pm"); + return(hh+":00"); + } + } + if (ii>=60000)//1 min + { if (nn<10) nn="0"+nn; + if (ttype==5) ;//You can add your own date format here + if (ttype==4) return((hh<=12) ? hh+"."+nn+"am" : hh%12+"."+nn+"pm"); + if (nn=="00") nn=""; + else nn=":"+nn; + if (ttype==3) return((hh<=12) ? hh+nn+"am" : hh%12+nn+"pm"); + if (nn=="") nn=":00"; + return(hh+nn); + } + if (ii>=1000)//1 sec + { if (nn<10) nn="0"+nn; + if (nn=="00") nn=""; + else nn=":"+nn; + if (ss<10) ss="0"+ss; + if (ss=="00") ss=""; + else ss=":"+ss; + if (ttype==5) ;//You can add your own date format here + if (ttype==4) return hh+nn+ss; + if (ttype==3) return((hh<=12) ? hh+nn+"am" : hh%12+nn+"pm"); + return(hh+nn); + } + if (ss<10) ss="0"+ss; + return(nn+":"+ss); +} +function _GetXGrid() +{ var x0,i,j,l,x,r,dx,xr,invdifx,deltax; + dx=(this.xmax-this.xmin); + if (Math.abs(dx)>0) + { invdifx=(this.right-this.left)/(this.xmax-this.xmin); + if ((this.XScale==1)||(isNaN(this.XScale))) + { r=1; + while (Math.abs(dx)>=100) { dx/=10; r*=10; } + while (Math.abs(dx)<10) { dx*=10; r/=10; } + if (Math.abs(dx)>=50) { this.SubGrids=5; deltax=10*r*_sign(dx); } + else + { if (Math.abs(dx)>=20) { this.SubGrids=5; deltax=5*r*_sign(dx); } + else { this.SubGrids=4; deltax=2*r*_sign(dx); } + } + } + else deltax=this.DateInterval(Math.abs(dx))*_sign(dx); + if (this.XGridDelta!=0) deltax=this.XGridDelta; + if (this.XSubGrids!=0) this.SubGrids=this.XSubGrids; + x=Math.floor(this.xmin/deltax)*deltax; + i=0; + this.XGrid[1]=deltax; + if (deltax!=0) this.MaxGrids=Math.floor(Math.abs((this.xmax-this.xmin)/deltax))+2; + else this.MaxGrids=0; + for (j=this.MaxGrids; j>=-1; j--) + { xr=x+j*deltax; + x0=Math.round(this.left+(-this.xmin+xr)*invdifx); + if ((x0>=this.left)&&(x0<=this.right)) + { if (i==0) this.XGrid[2]=xr; + this.XGrid[0]=xr; + i++; + } + } + } + return(this.XGrid); +} +function _GetYGrid() +{ var y0,i,j,l,y,r,dy,yr,invdify,deltay; + dy=this.ymax-this.ymin; + if (Math.abs(dy)>0) + { invdify=(this.bottom-this.top)/(this.ymax-this.ymin); + if ((this.YScale==1)||(isNaN(this.YScale))) + { r=1; + while (Math.abs(dy)>=100) { dy/=10; r*=10; } + while (Math.abs(dy)<10) { dy*=10; r/=10; } + if (Math.abs(dy)>=50) { this.SubGrids=5; deltay=10*r*_sign(dy); } + else + { if (Math.abs(dy)>=20) { this.SubGrids=5; deltay=5*r*_sign(dy); } + else { this.SubGrids=4; deltay=2*r*_sign(dy); } + } + } + else deltay=this.DateInterval(Math.abs(dy))*_sign(dy); + if (this.YGridDelta!=0) deltay=this.YGridDelta; + if (this.YSubGrids!=0) this.SubGrids=this.YSubGrids; + y=Math.floor(this.ymax/deltay)*deltay; + this.YGrid[1]=deltay; + i=0; + if (deltay!=0) this.MaxGrids=Math.floor(Math.abs((this.ymax-this.ymin)/deltay))+2; + else this.MaxGrids=0; + for (j=-1; j<=this.MaxGrids; j++) + { yr=y-j*deltay; + y0=Math.round(this.top+(this.ymax-yr)*invdify); + if ((y0>=this.top)&&(y0<=this.bottom)) + { if (i==0) this.YGrid[2]=yr; + this.YGrid[0]=yr; + i++; + } + } + } + return(this.YGrid); +} +function _nvl(vv, rr) +{ if (vv==null) return(rr); + var ss=String(vv); + while (ss.search("'")>=0) ss=ss.replace("'","'"); + return(ss); +} +function _cursor(aa) +{ if (aa) + { if (_dSize==1) return("cursor:hand;"); + else return("cursor:pointer;"); + } + return(""); +} +function _GetArrayMin(aa) +{ var ii, mm=aa[0]; + for (ii=1; iiaa[ii]) mm=aa[ii]; + } + return(mm); +} +function _GetArrayMax(aa) +{ var ii, mm=aa[0]; + for (ii=1; ii"); + if (_IsImage(theDrawColor)) + divtext="
"; + else + divtext="
 
"; + if ((this.XScale==1)||(isNaN(this.XScale))) + { u=""; + fn=""; + if (isNaN(this.XScale)) + { if (this.XScale.substr(0,9)=="function ") fn=eval("window."+this.XScale.substr(9)); + else u=this.XScale; + } + dx=(this.xmax-this.xmin); + if (Math.abs(dx)>0) + { invdifx=(this.right-this.left)/(this.xmax-this.xmin); + r=1; + while (Math.abs(dx)>=100) { dx/=10; r*=10; } + while (Math.abs(dx)<10) { dx*=10; r/=10; } + if (Math.abs(dx)>=50) { this.SubGrids=5; deltax=10*r*_sign(dx); } + else + { if (Math.abs(dx)>=20) { this.SubGrids=5; deltax=5*r*_sign(dx); } + else { this.SubGrids=4; deltax=2*r*_sign(dx); } + } + if (this.XGridDelta!=0) deltax=this.XGridDelta; + if (this.XSubGrids!=0) this.SubGrids=this.XSubGrids; + sub=deltax*invdifx/this.SubGrids; + sshift=0; + if ((this.XScalePosition=="top-left")||(this.XScalePosition=="bottom-left")) sshift=-Math.abs(deltax*invdifx/2); + if ((this.XScalePosition=="top-right")||(this.XScalePosition=="bottom-right")) sshift=Math.abs(deltax*invdifx/2); + x=Math.floor(this.xmin/deltax)*deltax; + itext=0; + if (deltax!=0) this.MaxGrids=Math.floor(Math.abs((this.xmax-this.xmin)/deltax))+2; + else this.MaxGrids=0; + for (j=this.MaxGrids; j>=-1; j--) + { xr=x+j*deltax; + x0=Math.round(this.left+(-this.xmin+xr)*invdifx); + if (this.XSubGridColor) + { for (k=1; kthis.left+1)&&(x0-k*sub
"; + } + if (this.SubGrids==-1) + for (k=0; k<8; k++) + { if ((x0-this.logsub[k]*sub*_sign(deltax)>this.left+1)&&(x0-this.logsub[k]*sub*_sign(deltax)
"; + } + } + if ((x0>=this.left)&&(x0<=this.right)) + { itext++; + if ((itext!=2)||(!isScaleText)) + { if (r>1) + { if (fn) l=fn(xr)+""; + else l=xr+""+u; + } + else + { if (fn) l=fn(Math.round(10*xr/r)/Math.round(10/r))+""; + else l=Math.round(10*xr/r)/Math.round(10/r)+""+u; + } + if (l.charAt(0)==".") l="0"+l; + if (l.substr(0,2)=="-.") l="-0"+l.substr(1,100); + } + else l=this.xtext; + if (this.XScalePosition.substr(0,3)!="top") + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + divtext+="
"+l+"
"; + divtext+="
"; + } + else + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + divtext+="
"+l+"
"; + divtext+="
"; + } + if ((this.XGridColor)&&(x0>this.left)&&(x0
"; + } + } + } + } + if ((!isNaN(this.XScale))&&(this.XScale>1)) + { dx=(this.xmax-this.xmin); + if (Math.abs(dx)>0) + { invdifx=(this.right-this.left)/(this.xmax-this.xmin); + deltax=this.DateInterval(Math.abs(dx))*_sign(dx); + if (this.XGridDelta!=0) deltax=this.XGridDelta; + if (this.XSubGrids!=0) this.SubGrids=this.XSubGrids; + sub=deltax*invdifx/this.SubGrids; + sshift=0; + if ((this.XScalePosition=="top-left")||(this.XScalePosition=="bottom-left")) sshift=-Math.abs(deltax*invdifx/2); + if ((this.XScalePosition=="top-right")||(this.XScalePosition=="bottom-right")) sshift=Math.abs(deltax*invdifx/2); + x=Math.floor(this.xmin/deltax)*deltax; + itext=0; + if (deltax!=0) this.MaxGrids=Math.floor(Math.abs((this.xmax-this.xmin)/deltax))+2; + else this.MaxGrids=0; + for (j=this.MaxGrids; j>=-2; j--) + { xr=x+j*deltax; + x0=Math.round(this.left+(-this.xmin+x+j*deltax)*invdifx); + if (this.XSubGridColor) + { for (k=1; kthis.left+1)&&(x0-k*sub"; + } + } + if ((x0>=this.left)&&(x0<=this.right)) + { itext++; + if ((itext!=2)||(!isScaleText)) l=_DateFormat(xr, Math.abs(deltax), this.XScale); + else l=this.xtext; + if (this.XScalePosition.substr(0,3)!="top") + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + divtext+="
"+l+"
"; + divtext+="
"; + } + else + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + divtext+="
"+l+"
"; + divtext+="
"; + } + if ((this.XGridColor)&&(x0>this.left)&&(x0"; + } + } + } + } + if ((this.YScale==1)||(isNaN(this.YScale))) + { u=""; + fn=""; + if (isNaN(this.YScale)) + { if (this.YScale.substr(0,9)=="function ") fn=eval("window."+this.YScale.substr(9)); + else u=this.YScale; + } + dy=this.ymax-this.ymin; + if (Math.abs(dy)>0) + { invdify=(this.bottom-this.top)/(this.ymax-this.ymin); + r=1; + while (Math.abs(dy)>=100) { dy/=10; r*=10; } + while (Math.abs(dy)<10) { dy*=10; r/=10; } + if (Math.abs(dy)>=50) { this.SubGrids=5; deltay=10*r*_sign(dy); } + else + { if (Math.abs(dy)>=20) { this.SubGrids=5; deltay=5*r*_sign(dy); } + else { this.SubGrids=4; deltay=2*r*_sign(dy); } + } + if (this.YGridDelta!=0) deltay=this.YGridDelta; + if (this.YSubGrids!=0) this.SubGrids=this.YSubGrids; + sub=deltay*invdify/this.SubGrids; + sshift=0; + if ((this.YScalePosition=="left-top")||(this.YScalePosition=="right-top")) sshift=-Math.abs(deltay*invdify/2); + if ((this.YScalePosition=="left-bottom")||(this.YScalePosition=="right-bottom")) sshift=Math.abs(deltay*invdify/2); + y=Math.floor(this.ymax/deltay)*deltay; + itext=0; + if (deltay!=0) this.MaxGrids=Math.floor(Math.abs((this.ymax-this.ymin)/deltay))+2; + else this.MaxGrids=0; + for (j=-1; j<=this.MaxGrids; j++) + { yr=y-j*deltay; + y0=Math.round(this.top+(this.ymax-yr)*invdify); + if (this.YSubGridColor) + { for (k=1; kthis.top+1)&&(y0+k*sub"+nbsp+""; + } + if (this.SubGrids==-1) + { for (k=0; k<8; k++) + { if ((y0+this.logsub[k]*sub*_sign(deltay)>this.top+1)&&(y0+this.logsub[k]*sub*_sign(deltay)"+nbsp+""; + } + } + } + if ((y0>=this.top)&&(y0<=this.bottom)) + { itext++; + if ((itext!=2)||(!isScaleText)) + { if (r>1) + { if (fn) l=fn(yr)+""; + else l=yr+""+u; + } + else + { if (fn) l=fn(Math.round(10*yr/r)/Math.round(10/r))+""; + else l=Math.round(10*yr/r)/Math.round(10/r)+""+u; + } + if (l.charAt(0)==".") l="0"+l; + if (l.substr(0,2)=="-.") l="-0"+l.substr(1,100); + } + else l=this.ytext; + if (this.YScalePosition.substr(0,5)!="right") + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + divtext+="
"+l+"
"; + divtext+="
"+nbsp+"
"; + } + else + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + divtext+="
"+l+"
"; + divtext+="
"+nbsp+"
"; + } + if ((this.YGridColor)&&(y0>this.top)&&(y0"+nbsp+""; + } + } + } + } + if ((!isNaN(this.YScale))&&(this.YScale>1)) + { dy=this.ymax-this.ymin; + if (Math.abs(dy)>0) + { invdify=(this.bottom-this.top)/(this.ymax-this.ymin); + deltay=this.DateInterval(Math.abs(dy))*_sign(dy); + if (this.YGridDelta!=0) deltay=this.YGridDelta; + if (this.YSubGrids!=0) this.SubGrids=this.YSubGrids; + sub=deltay*invdify/this.SubGrids; + sshift=0; + if ((this.YScalePosition=="left-top")||(this.YScalePosition=="right-top")) sshift=-Math.abs(deltay*invdify/2); + if ((this.YScalePosition=="left-bottom")||(this.YScalePosition=="right-bottom")) sshift=Math.abs(deltay*invdify/2); + y=Math.floor(this.ymax/deltay)*deltay; + itext=0; + if (deltay!=0) this.MaxGrids=Math.floor(Math.abs((this.ymax-this.ymin)/deltay))+2; + else this.MaxGrids=0; + for (j=-2; j<=this.MaxGrids; j++) + { yr=y-j*deltay; + y0=Math.round(this.top+(this.ymax-y+j*deltay)*invdify); + if (this.YSubGridColor) + { for (k=1; kthis.top+1)&&(y0+k*sub"+nbsp+""; + } + } + if ((y0>=this.top)&&(y0<=this.bottom)) + { itext++; + if ((itext!=2)||(!isScaleText)) l=_DateFormat(yr, Math.abs(deltay), this.YScale); + else l=this.ytext; + if (this.YScalePosition.substr(0,5)!="right") + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + divtext+="
"+l+"
"; + divtext+="
"+nbsp+"
"; + } + else + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + divtext+="
"+l+"
"; + divtext+="
"+nbsp+"
"; + } + if ((this.YGridColor)&&(y0>this.top)&&(y0"+nbsp+""; + } + } + } + } + if (this.XScalePosition.substr(0,3)!="top") + divtext+="
"+this.title+"
"; + else + divtext+="
"+this.title+"
"; + if (lay<-1) + selObj.innerHTML=divtext; + else + _DiagramTarget.document.writeln(divtext+""); +} + +function Bar(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Bar"+_N_Bar; _N_Bar++; _zIndex++; + this.left=theLeft; + this.top=theTop; + this.width=theRight-theLeft; + this.height=theBottom-theTop; + this.DrawColor=theDrawColor; + this.Text=String(theText); + this.TextColor=theTextColor; + this.BorderWidth=""; + this.BorderColor=""; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetBarColor; + this.SetText=_SetBarText; + this.SetTitle=_SetTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_ResizeTo; + this.Delete=_Delete; + var EventActions=""; + if (_nvl(theOnClickAction,"")!="") EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + if (_nvl(theText,"")!="") + { var tt=theText; + if (_IsImage(theText)) tt=""; + _DiagramTarget.document.writeln("
"+tt+"
"); + } + else + { var vv=(this.height>0) ? "" : ";visibility:hidden"; + _DiagramTarget.document.writeln("
 
"); + } + return(this); +} +function Box(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theBorderWidth, theBorderColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Box"+_N_Box; _N_Box++; _zIndex++; + this.left=theLeft; + this.top=theTop; + this.width=theRight-theLeft; + this.height=theBottom-theTop; + this.DrawColor=theDrawColor; + this.Text=String(theText); + this.TextColor=theTextColor; + this.BorderWidth=theBorderWidth; + this.BorderColor=theBorderColor; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetBarColor; + this.SetText=_SetBarText; + this.SetTitle=_SetTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_ResizeTo; + this.Delete=_Delete; + var EventActions=""; + if (_nvl(theOnClickAction,"")!="") EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var bb=""; + var ww=theBorderWidth; + if (_nvl(theBorderWidth,"")=="") ww=0; + if ((_nvl(theBorderWidth,"")!="")&&(_nvl(theBorderColor,"")!="")) + bb="border-style:solid;border-width:"+theBorderWidth+"px;border-color:"+theBorderColor+";"; + if (_nvl(theText,"")!="") + { var tt=theText; + if (_IsImage(theText)) tt=""; + _DiagramTarget.document.writeln("
"+tt+"
"); + } + else + { var vv=(this.height>=2*ww) ? "" : ";visibility:hidden"; + _DiagramTarget.document.writeln("
 
"); + } + return(this); +} +function _SetBarColor(theColor) +{ var id=this.ID, selObj; + this.DrawColor=theColor; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + selObj.style.backgroundColor=theColor; +} +function _SetBarText(theText) +{ var id=this.ID, selObj; + this.Text=String(theText); + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + var tt=theText; + if (_IsImage(theText)) + { var ww=0; + if (this.BorderWidth) ww=this.BorderWidth; + tt=""; + } + selObj.innerHTML=tt; +} +function Dot(theX, theY, theSize, theType, theColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.Size=theSize; + this.ID="Dot"+_N_Dot; _N_Dot++; _zIndex++; + this.X=theX; + this.Y=theY; + this.dX=Math.round(theSize/2); + this.dY=Math.round(theSize/2); + this.Type=theType; + this.Color=theColor; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetDotColor; + this.SetTitle=_SetTitle; + this.MoveTo=_DotMoveTo; + this.Delete=_Delete; + var EventActions=""; + if (_nvl(theOnClickAction,"")!="") EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + _DiagramTarget.document.write("
"); + if (isNaN(theType)) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + else + { if (theType%6==0) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + if (theType%6==1) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + if (theType%6==2) + _DiagramTarget.document.write("
"); + if (theType%6==3) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + if (theType%6==4) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + if (theType%6==5) + { if (_dSize==1) + _DiagramTarget.document.write("
"); + else + _DiagramTarget.document.write("
"); + } + } + _DiagramTarget.document.writeln("
"); + return(this); +} +function _SetDotColor(theColor) +{ this.Color=theColor; + var tt="", selObj; + if (document.all) selObj=eval("_DiagramTarget.document.all."+this.ID); + else selObj=_DiagramTarget.document.getElementById(this.ID); + if (isNaN(this.Type)) + { tt+="
"; + tt+="
"; + } + else + { if (this.Type%6==0) + { tt+="
"; + tt+="
"; + } + if (this.Type%6==1) + { tt+="
"; + tt+="
"; + } + if (this.Type%6==2) + tt+="
"; + if (this.Type%6==3) + { tt+="
"; + tt+="
"; + } + if (this.Type%6==4) + { tt+="
"; + tt+="
"; + } + if (this.Type%6==5) + { if (_dSize==1) + tt+="
"; + else + tt+="
"; + } + } + selObj.innerHTML=tt; +} +function _DotMoveTo(theX, theY) +{ var id=this.ID, selObj; + if (!isNaN(parseInt(theX))) this.X=theX; + if (!isNaN(parseInt(theY))) this.Y=theY; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (!isNaN(parseInt(theX))) left=eval(theX-this.dX)+"px"; + if (!isNaN(parseInt(theY))) top=eval(theY-this.dY)+"px"; + visibility="visible"; + } +} +function Pixel(theX, theY, theColor) +{ this.ID="Pix"+_N_Pix; _N_Pix++; _zIndex++; + this.left=theX; + this.top=theY; + this.dX=0; + this.dY=0; + this.Color=theColor; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetPixelColor; + this.MoveTo=_DotMoveTo; + this.Delete=_Delete; + _DiagramTarget.document.writeln("
"); + return(this); +} +function _SetPixelColor(theColor) +{ var id=this.ID, selObj; + this.Color=theColor; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + selObj.style.backgroundColor=theColor; +} +function _SetVisibility(isVisible) +{ var ll, id=this.ID, selObj; + if (document.all) + { selObj=eval("_DiagramTarget.document.all."+id); + if (isVisible) selObj.style.visibility="visible"; + else selObj.style.visibility="hidden"; + } + else + { selObj=_DiagramTarget.document.getElementById(id); + if (isVisible) selObj.style.visibility="visible"; + else selObj.style.visibility="hidden"; + if (id.substr(0,3)=='Dia') + { var ii=0; + selObj=_DiagramTarget.document.getElementById(id+'i'+eval(ii++)); + while (selObj!=null) + { if (isVisible) selObj.style.visibility="visible"; + else selObj.style.visibility="hidden"; + selObj=_DiagramTarget.document.getElementById(id+'i'+eval(ii++)); + } + } + } +} +function _SetTitle(theTitle) +{ var id=this.ID, selObj; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + selObj.title=theTitle; +} +function _MoveTo(theLeft, theTop) +{ var id=this.ID, selObj, ww=0; + if (this.BorderWidth) ww=this.BorderWidth; + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (!isNaN(parseInt(theLeft))) left=theLeft+"px"; + if (!isNaN(parseInt(theTop))) top=theTop+"px"; + if (this.height<=2*ww) visibility="hidden"; + else visibility="visible"; + } +} +function _ResizeTo(theLeft, theTop, theWidth, theHeight) +{ var id=this.ID, selObj, ww=0; + if (this.BorderWidth) ww=this.BorderWidth; + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + if (!isNaN(parseInt(theWidth))) this.width=theWidth; + if (!isNaN(parseInt(theHeight))) this.height=theHeight; + if (_IsImage(this.Text)) this.SetText(this.Text); + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (!isNaN(parseInt(theLeft))) left=theLeft+"px"; + if (!isNaN(parseInt(theTop))) top=theTop+"px"; + if (!isNaN(parseInt(theWidth))) width=eval(theWidth-ww+ww*_dSize)+"px"; + if (!isNaN(parseInt(theHeight))) height=eval(theHeight-ww+ww*_dSize)+"px"; + if (this.height<=2*ww) visibility="hidden"; + else visibility="visible"; + } +} +function _Delete() +{ var id=this.ID, selObj; + if (document.all) + { selObj=eval("_DiagramTarget.document.all."+id); + selObj.outerHTML=""; + } + else + { selObj=_DiagramTarget.document.getElementById(id); + selObj.parentNode.removeChild(selObj); + } +} +function _SetColor(theColor) +{ this.Color=theColor; + if ((theColor!="")&&(theColor.lengththis.Y0)&&(this.X1>this.X0))||((this.Y1"); + if ((ww==0)||(hh==0)) + _DiagramTarget.document.write("
"+nbsp+"
"); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + ccl++; + } + } + } + _DiagramTarget.document.writeln(""); + return(this); +} +function _LineResizeTo(theX0, theY0, theX1, theY1) +{ var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb, id=this.ID,selObj="",divtext=""; + var ss2=Math.floor(this.Size/2), nbsp="";//(_IE)? " " : ""; + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + var ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""; + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + ccl++; + } + } + } + selObj.innerHTML=divtext; +} +function _LineMoveTo(theLeft, theTop) +{ var id=this.ID, selObj; + var ss2=Math.floor(this.Size/2); + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (!isNaN(parseInt(theLeft))) left=eval(theLeft-ss2)+"px"; + if (!isNaN(parseInt(theTop))) top=eval(theTop-ss2)+"px"; + visibility="visible"; + } +} +//You can delete the following 2 functions, if you do not use Area objects +function Area(theX0, theY0, theX1, theY1, theColor, theBase, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Area"+_N_Area; _N_Area++; _zIndex++; + this.X0=theX0; + this.Y0=theY0; + this.X1=theX1; + this.Y1=theY1; + this.Color=theColor; + this.Base=theBase; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_AreaResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var dd, ll, rr, tt, bb, ww, hh; + if (theX0<=theX1) { ll=theX0; rr=theX1; } + else { ll=theX1; rr=theX0; } + if (theY0<=theY1) { tt=theY0; bb=theY1; } + else { tt=theY1; bb=theY0; } + ww=rr-ll; hh=bb-tt; + if (theBase<=tt) + _DiagramTarget.document.write("
"); + else + _DiagramTarget.document.write("
"); + if (theBase<=tt) + { if ((theBase0)) + _DiagramTarget.document.write("
"); + if (((theY0theY1)&&(theX0>theX1))) + _DiagramTarget.document.write("
"); + if (((theY0>theY1)&&(theX0theX1))) + _DiagramTarget.document.write("
"); + } + if ((theBase>tt)&&(theBasetheY1)&&(theX0>theX1))) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + if (((theY0>theY1)&&(theX0theX1))) + { _DiagramTarget.document.write("
"); + _DiagramTarget.document.write("
"); + } + } + if (theBase>=bb) + { if ((theBase>bb)&&(ww>0)) + _DiagramTarget.document.write("
"); + if (((theY0theY1)&&(theX0>theX1))) + _DiagramTarget.document.write("
"); + if (((theY0>theY1)&&(theX0theX1))) + _DiagramTarget.document.write("
"); + } + _DiagramTarget.document.writeln("
"); +} +function _AreaResizeTo(theX0, theY0, theX1, theY1) +{ var dd, ll, rr, tt, bb, ww, hh, id=this.ID,selObj="",divtext=""; + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + if (this.X0<=this.X1) { ll=this.X0; rr=this.X1; } + else { ll=this.X1; rr=this.X0; } + if (this.Y0<=this.Y1) { tt=this.Y0; bb=this.Y1; } + else { tt=this.Y1; bb=this.Y0; } + ww=rr-ll; hh=bb-tt; + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (this.Base<=tt) { left=ll+"px"; top=this.Base+"px"; width=ww+"px"; height=hh+"px"; } + else { left=ll+"px"; top=tt+"px"; width=ww+"px"; height=Math.max(hh, this.Base-tt)+"px";} + } + if (this.Base<=tt) + { if ((this.Base0)) + divtext+="
"; + if (((this.Y0this.Y1)&&(this.X0>this.X1))) + divtext+="
"; + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + divtext+="
"; + } + if ((this.Base>tt)&&(this.Basethis.Y1)&&(this.X0>this.X1))) + { divtext+="
"; + divtext+="
"; + } + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + { divtext+="
"; + divtext+="
"; + } + } + if (this.Base>=bb) + { if ((this.Base>bb)&&(ww>0)) + divtext+="
"; + if (((this.Y0this.Y1)&&(this.X0>this.X1))) + divtext+="
"; + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + divtext+="
"; + } + selObj.innerHTML=divtext; +} +//You can delete the following 3 functions, if you do not use Arrow objects +function Arrow(theX0, theY0, theX1, theY1, theColor, theSize, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Arrow"+_N_Arrow; _N_Arrow++; _zIndex++; + this.X0=theX0; + this.Y0=theY0; + this.X1=theX1; + this.Y1=theY1; + this.Color=theColor; + if ((theColor!="")&&(theColor.length==6)) this.Color="#"+theColor; + this.Size=Number(_nvl(theSize,1)); + this.Cursor=_cursor(theOnClickAction); + this.Border=8*this.Size; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_ArrowMoveTo; + this.ResizeTo=_ArrowResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb; + var ddir, ss2=Math.floor(this.Size/2), nbsp="";//(_IE)? " " : ""; + + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"); + if ((ww==0)||(hh==0)) + _DiagramTarget.document.write("
"+nbsp+"
"); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+"
"); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + ccl++; + } + } + } + var LL=1, ll0=ll, tt0=tt; + var ccL=8*theSize+4, ccB=2*theSize+1; + var DDX=theX1-theX0, DDY=theY1-theY0; + if ((DDX!=0)||(DDY!=0)) LL=Math.sqrt((DDX*DDX)+(DDY*DDY)); + this.X0=theX1-Math.round(1/LL*(ccL*DDX-ccB*DDY)); + this.Y0=theY1-Math.round(1/LL*(ccL*DDY+ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + ccl++; + } + } + } + this.X0=theX1-Math.round(1/LL*(ccL*DDX+ccB*DDY)); + this.Y0=theY1-Math.round(1/LL*(ccL*DDY-ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""); + else + _DiagramTarget.document.write("
"+nbsp+"
"); + ccl++; + } + } + } + _DiagramTarget.document.writeln(""); + this.X0=theX0; + this.Y0=theY0; + return(this); +} +function _ArrowResizeTo(theX0, theY0, theX1, theY1) +{ var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb, id=this.ID,selObj="",divtext=""; + var ss2=Math.floor(this.Size/2), nbsp="";//(_IE)? " " : ""; + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + var tmpX0=this.X0, tmpY0=this.Y0; + var ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""; + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + ccl++; + } + } + } + var LL=1, ll0=ll, tt0=tt; + var ccL=8*this.Size+4, ccB=2*this.Size+1; + var DDX=this.X1-tmpX0, DDY=this.Y1-tmpY0; + if ((DDX!=0)||(DDY!=0)) LL=Math.sqrt(0+(DDX*DDX)+(DDY*DDY)); + this.X0=this.X1-Math.round(1/LL*(ccL*DDX-ccB*DDY)); + this.Y0=this.Y1-Math.round(1/LL*(ccL*DDY+ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""; + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + ccl++; + } + } + } + this.X0=this.X1-Math.round(1/LL*(ccL*DDX+ccB*DDY)); + this.Y0=this.Y1-Math.round(1/LL*(ccL*DDY-ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+nbsp+""; + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"+nbsp+""; + else + divtext+="
"+nbsp+"
"; + ccl++; + } + } + } + selObj.innerHTML=divtext; + this.X0=tmpX0; + this.Y0=tmpY0; +} +function _ArrowMoveTo(theLeft, theTop) +{ var id=this.ID, selObj; + var ss2=Math.floor(this.Size/2); + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { if (!isNaN(parseInt(theLeft))) left=eval(theLeft-ss2-this.Border)+"px"; + if (!isNaN(parseInt(theTop))) top=eval(theTop-ss2-this.Border)+"px"; + visibility="visible"; + } +} +//You can delete the following 3 functions, if you do not use Pie objects +function Pie(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1, theColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Pie"+_N_Pie; _N_Pie++; _zIndex++; + this.XCenter=theXCenter; + this.YCenter=theYCenter; + this.Offset=theOffset; + this.Radius=theRadius; + this.dX=theRadius; + this.dY=theRadius; + this.Angle0=theAngle0; + this.Angle1=theAngle1; + this.Color=theColor; + if ((theColor!="")&&(theColor.length==6)) this.Color="#"+theColor; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_PieMoveTo; + this.ResizeTo=_PieResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+="onClick='"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var aa0, aa1, xx, yy, tt, xxo=0, yyo=0, rr2=this.Radius*this.Radius, xx0, yy0, xx1, yy1, pid180=Math.PI/180, ss0, ss1; + var nbsp="";//(_IE)? " " : ""; + aa0=this.Angle0; + aa1=this.Angle1; + while (aa0>=360) aa0-=360; + while (aa0<0) aa0+=360; + while (aa1>=360) aa1-=360; + while (aa1<0) aa1+=360; + if (aa0aa1) + { xxo=Math.sin((aa0+aa1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((aa0+aa1+360)*pid180/2)*this.Offset; + } + _DiagramTarget.document.write("
"); + if (aa0==aa1) + { if (this.Angle0"+nbsp+"
"); + } + } + } + else + { xx0=Math.sin(aa0*pid180)*this.Radius; + yy0=-Math.cos(aa0*pid180)*this.Radius; + xx1=Math.sin(aa1*pid180)*this.Radius; + yy1=-Math.cos(aa1*pid180)*this.Radius; + for (yy=-this.Radius; yy<0; yy++) + { xx=Math.round(Math.sqrt(rr2-(yy+0.5)*(yy+0.5))); + tt=yy+this.Radius; + if ((yy0>=0)&&(yy1>=0)) + { if (xx0"+nbsp+""); + } + else if ((yy0<0)&&(yy1<0)) + { if ((yy0))||((xx0<0)&&(xx1<=xx0))||((xx1>0)&&(xx0>=xx1))) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if ((yy>=yy0)&&(yy>=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0"+nbsp+""); + else + { _DiagramTarget.document.write("
"+nbsp+"
"); + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + else if (yy>=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else + { ss1=yy*xx1/yy1; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + else if (yy0<0) + { if (yy>=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if (xx0<0) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else + { if (yy>=yy1) + { ss1=yy*xx1/yy1; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if (xx1>0) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + for (yy=0; yyxx1) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if ((yy0>0)&&(yy1>0)) + { if ((yy>yy0)&&(yy>yy1)) + { if (((xx1<0)&&(xx0>0))||((xx1<0)&&(xx0<=xx1))||((xx0>0)&&(xx1>=xx0))) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if ((yy<=yy0)&&(yy<=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0>xx1) + _DiagramTarget.document.write("
"+nbsp+"
"); + else + { _DiagramTarget.document.write("
"+nbsp+"
"); + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + else if (yy<=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else + { ss1=yy*xx1/yy1; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + else if (yy0>0) + { if (yy<=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if (xx0>0) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else + { if (yy<=yy1) + { ss1=yy*xx1/yy1; + _DiagramTarget.document.write("
"+nbsp+"
"); + } + else if (xx1<0) + _DiagramTarget.document.write("
"+nbsp+"
"); + } + } + } + _DiagramTarget.document.writeln(""); + return(this); +} +function _PieResizeTo(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1) +{ var id=this.ID,selObj="",divtext=""; + if (!isNaN(parseInt(theXCenter))) this.XCenter=theXCenter; + if (!isNaN(parseInt(theYCenter))) this.YCenter=theYCenter; + if (!isNaN(parseInt(theOffset))) this.Offset=theOffset; + if (!isNaN(parseInt(theRadius))) this.Radius=theRadius; + if (!isNaN(parseInt(theAngle0))) this.Angle0=theAngle0; + if (!isNaN(parseInt(theAngle1))) this.Angle1=theAngle1; + var aa0, aa1, xx, yy, tt, xxo=0, yyo=0, rr2=this.Radius*this.Radius, xx0, yy0, xx1, yy1, pid180=Math.PI/180, ss0, ss1; + var nbsp="";//(_IE)? " " : ""; + aa0=this.Angle0; + aa1=this.Angle1; + if (aa0aa1) + { xxo=Math.sin((aa0+aa1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((aa0+aa1+360)*pid180/2)*this.Offset; + } + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { left=Math.round(this.XCenter-this.Radius+xxo)+"px"; + top=Math.round(this.YCenter-this.Radius+yyo)+"px"; + width=eval(2*this.Radius)+"px"; + height=eval(2*this.Radius)+"px"; + } + if (aa0==aa1) + { if (this.Angle0"+nbsp+""; + } + } + } + else + { xx0=Math.sin(aa0*pid180)*this.Radius; + yy0=-Math.cos(aa0*pid180)*this.Radius; + xx1=Math.sin(aa1*pid180)*this.Radius; + yy1=-Math.cos(aa1*pid180)*this.Radius; + for (yy=-this.Radius; yy<0; yy++) + { xx=Math.round(Math.sqrt(rr2-(yy+0.5)*(yy+0.5))); + tt=yy+this.Radius; + if ((yy0>=0)&&(yy1>=0)) + { if (xx0"+nbsp+""; + } + else if ((yy0<0)&&(yy1<0)) + { if ((yy0))||((xx0<0)&&(xx1<=xx0))||((xx1>0)&&(xx0>=xx1))) + divtext+="
"+nbsp+"
"; + } + else if ((yy>=yy0)&&(yy>=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0"+nbsp+""; + else + { divtext+="
"+nbsp+"
"; + divtext+="
"+nbsp+"
"; + } + } + else if (yy>=yy0) + { ss0=yy*xx0/yy0; + divtext+="
"+nbsp+"
"; + } + else + { ss1=yy*xx1/yy1; + divtext+="
"+nbsp+"
"; + } + } + else if (yy0<0) + { if (yy>=yy0) + { ss0=yy*xx0/yy0; + divtext+="
"+nbsp+"
"; + } + else if (xx0<0) + divtext+="
"+nbsp+"
"; + } + else + { if (yy>=yy1) + { ss1=yy*xx1/yy1; + divtext+="
"+nbsp+"
"; + } + else if (xx1>0) + divtext+="
"+nbsp+"
"; + } + } + for (yy=0; yyxx1) + divtext+="
"+nbsp+"
"; + } + else if ((yy0>0)&&(yy1>0)) + { if ((yy>yy0)&&(yy>yy1)) + { if (((xx1<0)&&(xx0>0))||((xx1<0)&&(xx0<=xx1))||((xx0>0)&&(xx1>=xx0))) + divtext+="
"+nbsp+"
"; + } + else if ((yy<=yy0)&&(yy<=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0>xx1) + divtext+="
"+nbsp+"
"; + else + { divtext+="
"+nbsp+"
"; + divtext+="
"+nbsp+"
"; + } + } + else if (yy<=yy0) + { ss0=yy*xx0/yy0; + divtext+="
"+nbsp+"
"; + } + else + { ss1=yy*xx1/yy1; + divtext+="
"+nbsp+"
"; + } + } + else if (yy0>0) + { if (yy<=yy0) + { ss0=yy*xx0/yy0; + divtext+="
"+nbsp+"
"; + } + else if (xx0>0) + divtext+="
"+nbsp+"
"; + } + else + { if (yy<=yy1) + { ss1=yy*xx1/yy1; + divtext+="
"+nbsp+"
"; + } + else if (xx1<0) + divtext+="
"+nbsp+"
"; + } + } + } + selObj.innerHTML=divtext; +} +function _PieMoveTo(theXCenter, theYCenter, theOffset) +{ var xxo=0, yyo=0, pid180=Math.PI/180, id=this.ID, selObj; + if (!isNaN(parseInt(theXCenter))) this.XCenter=theXCenter; + if (!isNaN(parseInt(theYCenter))) this.YCenter=theYCenter; + if (!isNaN(parseInt(theOffset))) this.Offset=theOffset; + if (this.Angle0this.Angle1) + { xxo=Math.sin((this.Angle0+this.Angle1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((this.Angle0+this.Angle1+360)*pid180/2)*this.Offset; + } + if (document.all) selObj=eval("_DiagramTarget.document.all."+id); + else selObj=_DiagramTarget.document.getElementById(id); + with (selObj.style) + { left=Math.round(this.XCenter-this.Radius+xxo)+"px"; + top=Math.round(this.YCenter-this.Radius+yyo)+"px"; + width=eval(2*this.Radius)+"px"; + height=eval(2*this.Radius)+"px"; + visibility="visible"; + } +} \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_nav.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_nav.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_nav.js 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,1465 @@ +// JavaScript Diagram Builder 3.31 +// Copyright (c) 2001-2005 Lutz Tautenhahn, all rights reserved. +// +// The Author grants you a non-exclusive, royalty free, license to use, +// modify and redistribute this software, provided that this copyright notice +// and license appear on all copies of the software. +// This software is provided "as is", without a warranty of any kind. + +function _Draw(theDrawColor, theTextColor, isScaleText, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ var x0,y0,i,j,itext,l,x,y,r,u,fn,dx,dy,xr,yr,invdifx,invdify,deltax,deltay,id=this.ID,lay=0,ii=0,oo,k,sub; + var c151="—"; + var EventActions=""; + if (_nvl(theOnClickAction,"")!="") EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + lay++; if (document.layers[id]) lay++; + var drawCol=(_nvl(theDrawColor,"")=="") ? "" : "bgcolor="+theDrawColor; + var drawImg='transparent.gif'; + if (_IsImage(theDrawColor)) { drawImg=theDrawColor; drawCol=""; } + if (lay>1) + { with(_DiagramTarget.document.layers[id]) + { top=this.top; + left=this.left; + document.open(); + document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + } + else + { _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + if ((this.XScale==1)||(isNaN(this.XScale))) + { u=""; + fn=""; + if (isNaN(this.XScale)) + { if (this.XScale.substr(0,9)=="function ") fn=eval("window."+this.XScale.substr(9)); + else u=this.XScale; + } + dx=(this.xmax-this.xmin); + if (Math.abs(dx)>0) + { invdifx=(this.right-this.left)/(this.xmax-this.xmin); + r=1; + while (Math.abs(dx)>=100) { dx/=10; r*=10; } + while (Math.abs(dx)<10) { dx*=10; r/=10; } + if (Math.abs(dx)>=50) { this.SubGrids=5; deltax=10*r*_sign(dx); } + else + { if (Math.abs(dx)>=20) { this.SubGrids=5; deltax=5*r*_sign(dx); } + else { this.SubGrids=4; deltax=2*r*_sign(dx); } + } + if (this.XGridDelta!=0) deltax=this.XGridDelta; + if (this.XSubGrids!=0) this.SubGrids=this.XSubGrids; + sub=deltax*invdifx/this.SubGrids; + sshift=0; + if ((this.XScalePosition=="top-left")||(this.XScalePosition=="bottom-left")) sshift=-Math.abs(deltax*invdifx/2); + if ((this.XScalePosition=="top-right")||(this.XScalePosition=="bottom-right")) sshift=Math.abs(deltax*invdifx/2); + x=Math.floor(this.xmin/deltax)*deltax; + itext=0; + if (deltax!=0) this.MaxGrids=Math.floor(Math.abs((this.xmax-this.xmin)/deltax))+2; + else this.MaxGrids=0; + for (j=this.MaxGrids; j>=-1; j--) + { xr=x+j*deltax; + x0=Math.round(this.left+(-this.xmin+xr)*invdifx); + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.XSubGridColor) + { for (k=1; kthis.left+1)&&(x0+k*sub
"); + } + if (this.SubGrids==-1) + { for (k=0; k<8; k++) + { if ((x0-this.logsub[k]*sub*_sign(deltax)>this.left+1)&&(x0-this.logsub[k]*sub*_sign(deltax)
"); + } + } + } + } + if ((x0>=this.left)&&(x0<=this.right)) + { itext++; + if ((itext!=2)||(!isScaleText)) + { if (r>1) + { if (fn) l=fn(xr)+""; + else l=xr+""+u; + } + else + { if (fn) l=fn(Math.round(10*xr/r)/Math.round(10/r))+""; + else l=Math.round(10*xr/r)/Math.round(10/r)+""+u; + } + if (l.charAt(0)==".") l="0"+l; + if (l.substr(0,2)=="-.") l="-0"+l.substr(1,100); + } + else l=this.xtext; + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.XScalePosition.substr(0,3)!="top") + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + writeln("
"+l+"
"); + writeln("
"); + } + else + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + writeln("
"+l+"
"); + writeln("
"); + } + if ((this.XGridColor)&&(x0>this.left)&&(x0
"); + } + } + } + } + } + if ((!isNaN(this.XScale))&&(this.XScale>1)) + { dx=(this.xmax-this.xmin); + if (Math.abs(dx)>0) + { invdifx=(this.right-this.left)/(this.xmax-this.xmin); + deltax=this.DateInterval(Math.abs(dx))*_sign(dx); + if (this.XGridDelta!=0) deltax=this.XGridDelta; + if (this.XSubGrids!=0) this.SubGrids=this.XSubGrids; + sub=deltax*invdifx/this.SubGrids; + sshift=0; + if ((this.XScalePosition=="top-left")||(this.XScalePosition=="bottom-left")) sshift=-Math.abs(deltax*invdifx/2); + if ((this.XScalePosition=="top-right")||(this.XScalePosition=="bottom-right")) sshift=Math.abs(deltax*invdifx/2); + x=Math.floor(this.xmin/deltax)*deltax; + itext=0; + if (deltax!=0) this.MaxGrids=Math.floor(Math.abs((this.xmax-this.xmin)/deltax))+2; + else this.MaxGrids=0; + for (j=this.MaxGrids; j>=-2; j--) + { xr=x+j*deltax; + x0=Math.round(this.left+(-this.xmin+x+j*deltax)*invdifx); + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.XSubGridColor) + { for (k=1; kthis.left+1)&&(x0+k*sub
"); + } + } + } + if ((x0>=this.left)&&(x0<=this.right)) + { itext++; + if ((itext!=2)||(!isScaleText)) l=_DateFormat(xr, Math.abs(deltax), this.XScale); + else l=this.xtext; + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.XScalePosition.substr(0,3)!="top") + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + writeln("
"+l+"
"); + writeln("
"); + } + else + { if ((x0+sshift>=this.left)&&(x0+sshift<=this.right)) + writeln("
"+l+"
"); + writeln("
"); + } + if ((this.XGridColor)&&(x0>this.left)&&(x0
"); + } + } + } + } + } + if ((this.YScale==1)||(isNaN(this.YScale))) + { u=""; + fn=""; + if (isNaN(this.YScale)) + { if (this.YScale.substr(0,9)=="function ") fn=eval("window."+this.YScale.substr(9)); + else u=this.YScale; + } + dy=this.ymax-this.ymin; + if (Math.abs(dy)>0) + { invdify=(this.bottom-this.top)/(this.ymax-this.ymin); + r=1; + while (Math.abs(dy)>=100) { dy/=10; r*=10; } + while (Math.abs(dy)<10) { dy*=10; r/=10; } + if (Math.abs(dy)>=50) { this.SubGrids=5; deltay=10*r*_sign(dy); } + else + { if (Math.abs(dy)>=20) { this.SubGrids=5; deltay=5*r*_sign(dy); } + else { this.SubGrids=4; deltay=2*r*_sign(dy); } + } + if (this.YGridDelta!=0) deltay=this.YGridDelta; + if (this.YSubGrids!=0) this.SubGrids=this.YSubGrids; + sub=deltay*invdify/this.SubGrids; + sshift=0; + if ((this.YScalePosition=="left-top")||(this.YScalePosition=="right-top")) sshift=-Math.abs(deltay*invdify/2); + if ((this.YScalePosition=="left-bottom")||(this.YScalePosition=="right-bottom")) sshift=Math.abs(deltay*invdify/2); + y=Math.floor(this.ymax/deltay)*deltay; + itext=0; + if (deltay!=0) this.MaxGrids=Math.floor(Math.abs((this.ymax-this.ymin)/deltay))+2; + else this.MaxGrids=0; + for (j=-1; j<=this.MaxGrids; j++) + { yr=y-j*deltay; + y0=Math.round(this.top+(this.ymax-yr)*invdify); + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.YSubGridColor) + { for (k=1; kthis.top+1)&&(y0+k*sub
"); + } + if (this.SubGrids==-1) + { for (k=0; k<8; k++) + { if ((y0+this.logsub[k]*sub*_sign(deltay)>this.top+1)&&(y0+this.logsub[k]*sub*_sign(deltay)
"); + } + } + } + } + if ((y0>=this.top)&&(y0<=this.bottom)) + { itext++; + if ((itext!=2)||(!isScaleText)) + { if (r>1) + { if (fn) l=fn(yr)+""; + else l=yr+""+u; + } + else + { if (fn) l=fn(Math.round(10*yr/r)/Math.round(10/r))+""; + else l=Math.round(10*yr/r)/Math.round(10/r)+""+u; + } + if (l.charAt(0)==".") l="0"+l; + if (l.substr(0,2)=="-.") l="-0"+l.substr(1,100); + } + else l=this.ytext; + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.YScalePosition.substr(0,5)!="right") + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + writeln("
"+l+"
"); + writeln("
"); + } + else + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + writeln("
"+l+"
"); + writeln("
"); + } + if ((this.YGridColor)&&(y0>this.top)&&(y0
"); + } + } + } + } + } + if ((!isNaN(this.YScale))&&(this.YScale>1)) + { dy=this.ymax-this.ymin; + if (Math.abs(dy)>0) + { invdify=(this.bottom-this.top)/(this.ymax-this.ymin); + deltay=this.DateInterval(Math.abs(dy))*_sign(dy); + if (this.YGridDelta!=0) deltay=this.YGridDelta; + if (this.YSubGrids!=0) this.SubGrids=this.YSubGrids; + sub=deltay*invdify/this.SubGrids; + sshift=0; + if ((this.YScalePosition=="left-top")||(this.YScalePosition=="right-top")) sshift=-Math.abs(deltay*invdify/2); + if ((this.YScalePosition=="left-bottom")||(this.YScalePosition=="right-bottom")) sshift=Math.abs(deltay*invdify/2); + y=Math.floor(this.ymax/deltay)*deltay; + itext=0; + if (deltay!=0) this.MaxGrids=Math.floor(Math.abs((this.ymax-this.ymin)/deltay))+2; + else this.MaxGrids=0; + for (j=-2; j<=this.MaxGrids; j++) + { yr=y-j*deltay; + y0=Math.round(this.top+(this.ymax-y+j*deltay)*invdify); + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.YSubGridColor) + { for (k=1; kthis.top+1)&&(y0+k*sub
"); + } + } + } + if ((y0>=this.top)&&(y0<=this.bottom)) + { itext++; + if ((itext!=2)||(!isScaleText)) l=_DateFormat(yr, Math.abs(deltay), this.YScale); + else l=this.ytext; + if (lay>1) oo=_DiagramTarget.document.layers[id]; + else oo=_DiagramTarget; + with(oo.document) + { if (this.YScalePosition.substr(0,5)!="right") + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + writeln("
"+l+"
"); + writeln("
"); + } + else + { if ((y0+sshift>=this.top)&&(y0+sshift<=this.bottom)) + writeln("
"+l+"
"); + writeln("
"); + } + if ((this.YGridColor)&&(y0>this.top)&&(y0
"); + } + } + } + } + } + if (lay>1) + { with(_DiagramTarget.document.layers[id]) + { if (this.XScalePosition.substr(0,3)!="top") + document.writeln("
"+this.title+"
"); + else + document.writeln("
"+this.title+"
"); + document.close(); + } + } + else + { if (this.XScalePosition.substr(0,3)!="top") + _DiagramTarget.document.writeln("
"+this.title+"
"); + else + _DiagramTarget.document.writeln("
"+this.title+"
"); + _DiagramTarget.document.writeln("
"); + } +} + +function Bar(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Bar"+_N_Bar; _N_Bar++; _zIndex++; + this.left=theLeft; + this.top=theTop; + this.width=theRight-theLeft; + this.height=theBottom-theTop; + this.DrawColor=theDrawColor; + this.Text=String(theText); + this.TextColor=theTextColor; + this.BorderWidth=0; + this.BorderColor=""; + this.TooltipText=theTooltipText; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetBarColor; + this.SetText=_SetBarText; + this.SetTitle=_SetBarTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_ResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var tt=""; + while (tt.length"; + else tt=this.Text; + if (_IsImage(this.Text)) tt=""+_nvl(theTooltipText,"")+""; + var drawCol=(_nvl(theDrawColor,"")=="") ? "" : "bgcolor="+theDrawColor; + var textCol=(_nvl(theTextColor,"")=="") ? "" : "color:"+theTextColor+";"; + var vv=(this.height>1) ? "" : " visibility=hide"; + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln("
"+tt+"
"); + _DiagramTarget.document.writeln("
"); + return(this); +} +function Box(theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theBorderWidth, theBorderColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Box"+_N_Box; _N_Box++; _zIndex++; + this.left=theLeft; + this.top=theTop; + this.width=theRight-theLeft; + this.height=theBottom-theTop; + this.DrawColor=theDrawColor; + this.Text=String(theText); + this.TextColor=theTextColor; + this.BorderWidth=theBorderWidth; + this.BorderColor=theBorderColor; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetBarColor; + this.SetText=_SetBarText; + this.SetTitle=_SetBarTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_ResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var bb=""; + var ww=theBorderWidth; + if (_nvl(theBorderWidth,"")=="") ww=0; + if ((_nvl(theBorderWidth,"")!="")&&(_nvl(theBorderColor,"")!="")) + bb="bordercolor="+theBorderColor; + var tt=""; + while (tt.length"; + else tt=this.Text; + if (_IsImage(this.Text)) tt=""+_nvl(theTooltipText,"")+""; + var drawCol=(_nvl(theDrawColor,"")=="") ? "" : "bgcolor="+theDrawColor; + var textCol=(_nvl(theTextColor,"")=="") ? "" : "color:"+theTextColor+";"; + var vv=(this.height>2*ww+1) ? "" : " visibility=hide"; + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln("
"+tt+"
"); + _DiagramTarget.document.writeln("
"); + return(this); +} +function _SetBarColor(theColor) +{ var id=this.ID; + this.DrawColor=theColor; + var ww=this.BorderWidth; + if (_nvl(this.BorderWidth,"")=="") ww=0; + var tt=""; + while (tt.length"; + else tt=this.Text; + if (_IsImage(this.Text)) tt=""+_nvl(this.TooltipText,"")+""; + var drawCol=(_nvl(this.DrawColor,"")=="") ? "" : "bgcolor="+this.DrawColor; + var textCol=(_nvl(this.TextColor,"")=="") ? "" : "color:"+this.TextColor+";"; + with(_DiagramTarget.document.layers[id]) + { document.open(); + if ((_nvl(this.BorderWidth,"")!="")&&(_nvl(this.BorderColor,"")!="")) + document.writeln("
"+tt+"
"); + else + document.writeln("
"+tt+"
"); + document.close(); + } +} +function _SetBarTitle(theTitle) +{ this.TooltipText=theTitle; + this.SetColor(this.DrawColor); +} +function _SetBarText(theText) +{ var id=this.ID; + this.Text=String(theText); + var ww=this.BorderWidth; + if (_nvl(this.BorderWidth,"")=="") ww=0; + var tt=""; + while (tt.length"; + else tt=this.Text; + if (_IsImage(this.Text)) tt=""+_nvl(this.TooltipText,"")+""; + var drawCol=(_nvl(this.DrawColor,"")=="") ? "" : "bgcolor="+this.DrawColor; + var textCol=(_nvl(this.TextColor,"")=="") ? "" : "color:"+this.TextColor+";"; + with(_DiagramTarget.document.layers[id]) + { document.open(); + if ((_nvl(this.BorderWidth,"")!="")&&(_nvl(this.BorderColor,"")!="")) + document.writeln("
"+tt+"
"); + else + document.writeln("
"+tt+"
"); + document.close(); + } +} +function Dot(theX, theY, theSize, theType, theColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.Size=theSize; + this.ID="Dot"+_N_Dot; _N_Dot++; _zIndex++; + this.X=theX; + this.Y=theY; + this.dX=Math.round(theSize/2); + this.dY=Math.round(theSize/2); + this.Type=theType; + this.Color=theColor; + this.TooltipText=theTooltipText; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetDotColor; + this.SetTitle=_SetDotTitle; + this.MoveTo=_DotMoveTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + _DiagramTarget.document.writeln(""); + if (isNaN(theType)) + { var cc=(_nvl(theColor,"")=="") ? "" : " bgcolor="+theColor; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+"
"); + } + else + { if (theType%6==0) + { _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + if (theType%6==1) + { _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + if (theType%6==2) + _DiagramTarget.document.writeln("
"); + if (theType%6==3) + { _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + if (theType%6==4) + { _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + _DiagramTarget.document.writeln("
"+_nvl(theTooltipText,"")+"
"); + } + if (theType%6==5) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + _DiagramTarget.document.writeln("
"); + return(this); +} +function _SetDotColor(theColor) +{ if (theColor!="") this.Color=theColor; + with(_DiagramTarget.document.layers[this.ID]) + { document.open(); + if (isNaN(this.Type)) + { var cc=(_nvl(this.Color,"")=="") ? "" : " bgcolor="+this.Color; + document.writeln(""+_nvl(this.TooltipText,"")+"
"); + } + else + { if (this.Type%6==0) + { document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + } + if (this.Type%6==1) + { document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + } + if (this.Type%6==2) + document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + if (this.Type%6==3) + { document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + } + if (this.Type%6==4) + { document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + document.writeln("
"+_nvl(this.TooltipText,"")+"
"); + } + if (this.Type%6==5) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + document.close(); + } +} +function _SetDotTitle(theTitle) +{ this.TooltipText=theTitle; + this.SetColor(""); +} +function _DotMoveTo(theX, theY) +{ var id=this.ID; + if (!isNaN(parseInt(theX))) this.X=theX; + if (!isNaN(parseInt(theY))) this.Y=theY; + with(_DiagramTarget.document.layers[id]) + { if (!isNaN(parseInt(theX))) left=eval(theX-this.dX); + if (!isNaN(parseInt(theY))) top=eval(theY-this.dY); + visibility="show"; + } +} +function Pixel(theX, theY, theColor) +{ this.ID="Pix"+_N_Pix; _N_Pix++; _zIndex++; + this.left=theX; + this.top=theY; + this.dX=2; + this.dY=2; + this.Color=theColor; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetPixelColor; + this.MoveTo=_DotMoveTo; + this.Delete=_Delete; + _DiagramTarget.document.writeln(""); + return(this); +} +function _SetPixelColor(theColor) +{ this.Color=theColor; + with(_DiagramTarget.document.layers[this.ID]) + { document.open(); + document.writeln(""); + document.close(); + } +} +function _SetVisibility(isVisible) +{ var ll, id=this.ID; + with(_DiagramTarget.document.layers[id]) + { if (isVisible) visibility="show"; + else visibility="hide"; + } +} +function _SetTitle(theTitle) +{ this.TooltipText=theTitle; + if (this.ResizeTo) this.ResizeTo("","","",""); +} +function _MoveTo(theLeft, theTop) +{ var id=this.ID; + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + var ww=this.BorderWidth; + if (_nvl(this.BorderWidth,"")=="") ww=0; + with(_DiagramTarget.document.layers[id]) + { if (!isNaN(parseInt(theLeft))) left=theLeft; + if (!isNaN(parseInt(theTop))) top=theTop; + if (this.height<=2*ww+1) visibility="hide"; + else visibility="show"; + } +} +function _ResizeTo(theLeft, theTop, theWidth, theHeight) +{ var id=this.ID; + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + if (!isNaN(parseInt(theWidth))) this.width=theWidth; + if (!isNaN(parseInt(theHeight))) this.height=theHeight; + var ww=this.BorderWidth; + if (_nvl(this.BorderWidth,"")=="") ww=0; + var tt=""; + while (tt.length"; + else tt=this.Text; + if (_IsImage(this.Text)) tt=""+_nvl(this.TooltipText,"")+""; + var drawCol=(_nvl(this.DrawColor,"")=="") ? "" : "bgcolor="+this.DrawColor; + var textCol=(_nvl(this.TextColor,"")=="") ? "" : "color:"+this.TextColor+";"; + with(_DiagramTarget.document.layers[id]) + { top=this.top; + left=this.left; + if (this.height<=2*ww+1) visibility="hide"; + else visibility="show"; + document.open(); + if ((_nvl(this.BorderWidth,"")!="")&&(_nvl(this.BorderColor,"")!="")) + document.writeln("
"+tt+"
"); + else + document.writeln("
"+tt+"
"); + document.close(); + } +} +function _Delete() +{ var id=this.ID; + with(_DiagramTarget.document.layers[id]) + { document.open(); + document.close(); + } +} +function _SetColor(theColor) +{ this.Color=theColor; + if ((theColor!="")&&(theColor.lengththis.Y0)&&(this.X1>this.X0))||((this.Y1"); + if ((ww==0)||(hh==0)) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + ccl++; + } + } + } + _DiagramTarget.document.writeln(""); + return(this); +} +function _LineResizeTo(theX0, theY0, theX1, theY1) +{ var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb, id=this.ID; + var ss2=Math.floor(this.Size/2); + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + var ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(this.TooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + ccl++; + } + } + } + document.close(); + } +} +function _LineMoveTo(theLeft, theTop) +{ var id=this.ID; + var ss2=Math.floor(this.Size/2); + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + with(_DiagramTarget.document.layers[id]) + { if (!isNaN(parseInt(theLeft))) left=theLeft-ss2; + if (!isNaN(parseInt(theTop))) top=theTop-ss2; + visibility="show"; + } +} +//You can delete the following 2 functions, if you do not use Area objects +function Area(theX0, theY0, theX1, theY1, theColor, theBase, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Area"+_N_Area; _N_Area++; _zIndex++; + this.X0=theX0; + this.Y0=theY0; + this.X1=theX1; + this.Y1=theY1; + this.Color=theColor; + this.Base=theBase; + this.TooltipText=theTooltipText; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_MoveTo; + this.ResizeTo=_AreaResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var dd, ll, rr, tt, bb, ww, hh; + if (theX0<=theX1) { ll=theX0; rr=theX1; } + else { ll=theX1; rr=theX0; } + if (theY0<=theY1) { tt=theY0; bb=theY1; } + else { tt=theY1; bb=theY0; } + ww=rr-ll; hh=bb-tt; + if (theBase<=tt) + _DiagramTarget.document.writeln(""); + else + _DiagramTarget.document.writeln(""); + if (theBase<=tt) + { if ((theBase0)) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + if (((theY0theY1)&&(theX0>theX1))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + if (((theY0>theY1)&&(theX0theX1))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + if ((theBase>tt)&&(theBasetheY1)&&(theX0>theX1))) + { _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + if (((theY0>theY1)&&(theX0theX1))) + { _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + if (theBase>=bb) + { if ((theBase>bb)&&(ww>0)) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + if (((theY0theY1)&&(theX0>theX1))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + if (((theY0>theY1)&&(theX0theX1))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + _DiagramTarget.document.writeln(""); +} +function _AreaResizeTo(theX0, theY0, theX1, theY1) +{ var dd, ll, rr, tt, bb, ww, hh, id=this.ID; + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + if (this.X0<=this.X1) { ll=this.X0; rr=this.X1; } + else { ll=this.X1; rr=this.X0; } + if (this.Y0<=this.Y1) { tt=this.Y0; bb=this.Y1; } + else { tt=this.Y1; bb=this.Y0; } + ww=rr-ll; hh=bb-tt; + with(_DiagramTarget.document.layers[id]) + { if (this.Base<=tt) { left=ll; top=this.Base; } + else { left=ll; top=tt; } + document.open(); + if (this.Base<=tt) + { if ((this.Base0)) + document.writeln(""+_nvl(this.TooltipText,"")+""); + if (((this.Y0this.Y1)&&(this.X0>this.X1))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + if ((this.Base>tt)&&(this.Basethis.Y1)&&(this.X0>this.X1))) + { document.writeln(""+_nvl(this.TooltipText,"")+""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + { document.writeln(""+_nvl(this.TooltipText,"")+""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + if (this.Base>=bb) + { if ((this.Base>bb)&&(ww>0)) + document.writeln(""+_nvl(this.TooltipText,"")+""); + if (((this.Y0this.Y1)&&(this.X0>this.X1))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + if (((this.Y0>this.Y1)&&(this.X0this.X1))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + document.close(); + } +} +//You can delete the following 3 functions, if you do not use Arrow objects +function Arrow(theX0, theY0, theX1, theY1, theColor, theSize, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Arrow"+_N_Arrow; _N_Arrow++; _zIndex++; + this.X0=theX0; + this.Y0=theY0; + this.X1=theX1; + this.Y1=theY1; + this.Color=theColor; + if ((theColor!="")&&(theColor.length==6)) this.Color="#"+theColor; + this.Size=Number(_nvl(theSize,1)); + this.TooltipText=theTooltipText; + this.Border=8*this.Size; + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_ArrowMoveTo; + this.ResizeTo=_ArrowResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb; + var ss2=Math.floor(this.Size/2); + var ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"); + if ((ww==0)||(hh==0)) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + ccl++; + } + } + } + var LL=1, ll0=ll, tt0=tt; + var ccL=8*theSize+4, ccB=2*theSize+1; + var DDX=theX1-theX0, DDY=theY1-theY0; + if ((DDX!=0)||(DDY!=0)) LL=Math.sqrt((DDX*DDX)+(DDY*DDY)); + this.X0=theX1-Math.round(1/LL*(ccL*DDX-ccB*DDY)); + this.Y0=theY1-Math.round(1/LL*(ccL*DDY+ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(theTooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + ccl++; + } + } + } + this.X0=theX1-Math.round(1/LL*(ccL*DDX+ccB*DDY)); + this.Y0=theY1-Math.round(1/LL*(ccL*DDY-ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(theTooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + _DiagramTarget.document.writeln(""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + ccl++; + } + } + } + _DiagramTarget.document.writeln(""); + this.X0=theX0; + this.Y0=theY0; + return(this); +} +function _ArrowResizeTo(theX0, theY0, theX1, theY1) +{ var xx0, yy0, xx1, yy1, ll, rr, tt, bb, ww, hh, ccl, ccr, cct, ccb, id=this.ID; + var ss2=Math.floor(this.Size/2); + if (!isNaN(parseInt(theX0))) this.X0=theX0; + if (!isNaN(parseInt(theY0))) this.Y0=theY0; + if (!isNaN(parseInt(theX1))) this.X1=theX1; + if (!isNaN(parseInt(theY1))) this.Y1=theY1; + var tmpX0=this.X0, tmpY0=this.Y0; + var ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(this.TooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + ccl++; + } + } + } + var LL=1, ll0=ll, tt0=tt; + var ccL=8*this.Size+4, ccB=2*this.Size+1; + var DDX=this.X1-tmpX0, DDY=this.Y1-tmpY0; + if ((DDX!=0)||(DDY!=0)) LL=Math.sqrt(0+(DDX*DDX)+(DDY*DDY)); + this.X0=this.X1-Math.round(1/LL*(ccL*DDX-ccB*DDY)); + this.Y0=this.Y1-Math.round(1/LL*(ccL*DDY+ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(this.TooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + ccl++; + } + } + } + this.X0=this.X1-Math.round(1/LL*(ccL*DDX+ccB*DDY)); + this.Y0=this.Y1-Math.round(1/LL*(ccL*DDY-ccB*DDX)); + ddir=(((this.Y1>this.Y0)&&(this.X1>this.X0))||((this.Y1"+_nvl(this.TooltipText,"")+""); + else + { if (ww>hh) + { ccr=0; + cct=0; + while (ccr"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + cct++; + } + } + else + { ccb=0; + ccl=0; + while (ccb"); + else + document.writeln(""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + ccl++; + } + } + } + document.close(); + } + this.X0=tmpX0; + this.Y0=tmpY0; +} +function _ArrowMoveTo(theLeft, theTop) +{ var id=this.ID; + var ss2=Math.floor(this.Size/2); + if (!isNaN(parseInt(theLeft))) this.left=theLeft; + if (!isNaN(parseInt(theTop))) this.top=theTop; + with(_DiagramTarget.document.layers[id]) + { if (!isNaN(parseInt(theLeft))) left=theLeft-ss2-this.Border; + if (!isNaN(parseInt(theTop))) top=theTop-ss2-this.Border; + visibility="show"; + } +} +//You can delete the following 3 functions, if you do not use Pie objects +function Pie(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1, theColor, theTooltipText, theOnClickAction, theOnMouseoverAction, theOnMouseoutAction) +{ this.ID="Pie"+_N_Pie; _N_Pie++; _zIndex++; + this.XCenter=theXCenter; + this.YCenter=theYCenter; + this.Offset=theOffset; + this.Radius=theRadius; + this.dX=theRadius; + this.dY=theRadius; + this.Angle0=theAngle0; + this.Angle1=theAngle1; + this.Color=theColor; + if ((theColor!="")&&(theColor.length==6)) this.Color="#"+theColor; + this.TooltipText=theTooltipText; + this.Cursor=_cursor(theOnClickAction); + this.SetVisibility=_SetVisibility; + this.SetColor=_SetColor; + this.SetTitle=_SetTitle; + this.MoveTo=_PieMoveTo; + this.ResizeTo=_PieResizeTo; + this.Delete=_Delete; + this.EventActions=""; + if (_nvl(theOnClickAction,"")!="") this.EventActions+=" href='javascript:"+_nvl(theOnClickAction,"")+"' "; + if (_nvl(theOnMouseoverAction,"")!="") this.EventActions+="onMouseover='"+_nvl(theOnMouseoverAction,"")+"' "; + if (_nvl(theOnMouseoutAction,"")!="") this.EventActions+="onMouseout='"+_nvl(theOnMouseoutAction,"")+"' "; + var aa0, aa1, xx, yy, tt, xxo=0, yyo=0, rr2=this.Radius*this.Radius, xx0, yy0, xx1, yy1, pid180=Math.PI/180, ss0, ss1; + var nbsp="";//(_IE)? " " : ""; + aa0=this.Angle0; + aa1=this.Angle1; + while (aa0>=360) aa0-=360; + while (aa0<0) aa0+=360; + while (aa1>=360) aa1-=360; + while (aa1<0) aa1+=360; + if (aa0aa1) + { xxo=Math.sin((aa0+aa1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((aa0+aa1+360)*pid180/2)*this.Offset; + } + _DiagramTarget.document.writeln(""); + if (aa0==aa1) + { if (this.Angle0"+_nvl(theTooltipText,"")+""); + } + } + } + else + { xx0=Math.sin(aa0*pid180)*this.Radius; + yy0=-Math.cos(aa0*pid180)*this.Radius; + xx1=Math.sin(aa1*pid180)*this.Radius; + yy1=-Math.cos(aa1*pid180)*this.Radius; + for (yy=-this.Radius; yy<0; yy++) + { xx=Math.round(Math.sqrt(rr2-(yy+0.5)*(yy+0.5))); + tt=yy+this.Radius+2; + if ((yy0>=0)&&(yy1>=0)) + { if (xx0"+_nvl(theTooltipText,"")+""); + } + else if ((yy0<0)&&(yy1<0)) + { if ((yy0))||((xx0<0)&&(xx1<=xx0))||((xx1>0)&&(xx0>=xx1))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if ((yy>=yy0)&&(yy>=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0"+_nvl(theTooltipText,"")+""); + else + { _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + else if (yy>=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else + { ss1=yy*xx1/yy1; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + else if (yy0<0) + { if (yy>=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if (xx0<0) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else + { if (yy>=yy1) + { ss1=yy*xx1/yy1; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if (xx1>0) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + for (yy=0; yyxx1) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if ((yy0>0)&&(yy1>0)) + { if ((yy>yy0)&&(yy>yy1)) + { if (((xx1<0)&&(xx0>0))||((xx1<0)&&(xx0<=xx1))||((xx0>0)&&(xx1>=xx0))) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if ((yy<=yy0)&&(yy<=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0>xx1) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + else + { _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + else if (yy<=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else + { ss1=yy*xx1/yy1; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + else if (yy0>0) + { if (yy<=yy0) + { ss0=yy*xx0/yy0; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if (xx0>0) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else + { if (yy<=yy1) + { ss1=yy*xx1/yy1; + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + else if (xx1<0) + _DiagramTarget.document.writeln(""+_nvl(theTooltipText,"")+""); + } + } + } + _DiagramTarget.document.writeln(""); + return(this); +} +function _PieResizeTo(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1) +{ var id=this.ID; + if (!isNaN(parseInt(theXCenter))) this.XCenter=theXCenter; + if (!isNaN(parseInt(theYCenter))) this.YCenter=theYCenter; + if (!isNaN(parseInt(theOffset))) this.Offset=theOffset; + if (!isNaN(parseInt(theRadius))) this.Radius=theRadius; + if (!isNaN(parseInt(theAngle0))) this.Angle0=theAngle0; + if (!isNaN(parseInt(theAngle1))) this.Angle1=theAngle1; + var aa0, aa1, xx, yy, xxo=0, yyo=0, rr2=this.Radius*this.Radius, xx0, yy0, xx1, yy1, pid180=Math.PI/180, ss0, ss1; + var nbsp="";//(_IE)? " " : ""; + aa0=this.Angle0; + aa1=this.Angle1; + if (aa0aa1) + { xxo=Math.sin((aa0+aa1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((aa0+aa1+360)*pid180/2)*this.Offset; + } + with(_DiagramTarget.document.layers[id]) + { top=Math.round(this.YCenter-this.Radius+yyo); + left=Math.round(this.XCenter-this.Radius+xxo); + document.open(); + if (aa0==aa1) + { if (this.Angle0"+_nvl(this.TooltipText,"")+""); + } + } + } + else + { xx0=Math.sin(aa0*pid180)*this.Radius; + yy0=-Math.cos(aa0*pid180)*this.Radius; + xx1=Math.sin(aa1*pid180)*this.Radius; + yy1=-Math.cos(aa1*pid180)*this.Radius; + for (yy=-this.Radius; yy<0; yy++) + { xx=Math.round(Math.sqrt(rr2-(yy+0.5)*(yy+0.5))); + tt=yy+this.Radius+2; + if ((yy0>=0)&&(yy1>=0)) + { if (xx0"+_nvl(this.TooltipText,"")+""); + } + else if ((yy0<0)&&(yy1<0)) + { if ((yy0))||((xx0<0)&&(xx1<=xx0))||((xx1>0)&&(xx0>=xx1))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if ((yy>=yy0)&&(yy>=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0"+_nvl(this.TooltipText,"")+""); + else + { document.writeln(""+_nvl(this.TooltipText,"")+""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + else if (yy>=yy0) + { ss0=yy*xx0/yy0; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else + { ss1=yy*xx1/yy1; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + else if (yy0<0) + { if (yy>=yy0) + { ss0=yy*xx0/yy0; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if (xx0<0) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else + { if (yy>=yy1) + { ss1=yy*xx1/yy1; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if (xx1>0) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + for (yy=0; yyxx1) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if ((yy0>0)&&(yy1>0)) + { if ((yy>yy0)&&(yy>yy1)) + { if (((xx1<0)&&(xx0>0))||((xx1<0)&&(xx0<=xx1))||((xx0>0)&&(xx1>=xx0))) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if ((yy<=yy0)&&(yy<=yy1)) + { ss0=yy*xx0/yy0; + ss1=yy*xx1/yy1; + if (xx0>xx1) + document.writeln(""+_nvl(this.TooltipText,"")+""); + else + { document.writeln(""+_nvl(this.TooltipText,"")+""); + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + else if (yy<=yy0) + { ss0=yy*xx0/yy0; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else + { ss1=yy*xx1/yy1; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + else if (yy0>0) + { if (yy<=yy0) + { ss0=yy*xx0/yy0; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if (xx0>0) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else + { if (yy<=yy1) + { ss1=yy*xx1/yy1; + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + else if (xx1<0) + document.writeln(""+_nvl(this.TooltipText,"")+""); + } + } + } + document.close(); + } +} +function _PieMoveTo(theXCenter, theYCenter, theOffset) +{ var xxo=0, yyo=0, pid180=Math.PI/180, id=this.ID; + if (!isNaN(parseInt(theXCenter))) this.XCenter=theXCenter; + if (!isNaN(parseInt(theYCenter))) this.YCenter=theYCenter; + if (!isNaN(parseInt(theOffset))) this.Offset=theOffset; + if (this.Angle0this.Angle1) + { xxo=Math.sin((this.Angle0+this.Angle1+360)*pid180/2)*this.Offset; + yyo=-Math.cos((this.Angle0+this.Angle1+360)*pid180/2)*this.Offset; + } + with(_DiagramTarget.document.layers[id]) + { left=Math.round(this.XCenter-this.Radius+xxo); + top=Math.round(this.YCenter-this.Radius+yyo); + visibility="show"; + } +} \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/diagram_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,164 @@ + + + +JavaScript Diagram Builder - The Diagram object + + + + + +
+
+

JavaScript Diagram Builder - The Diagram object

+
+The Diagram object provides the possibility, to draw a diagram at a defined position with a defined size on the +window document. The appropriate scale will be drawn automatically, corresponding to the specified xmin, xmax, ymin +and ymax values. The diagram provides - also when not drawn - some useful functions which can be used to transform +screen positions into real world positions and vice versa. +
+ +
+This diagram was generated by
+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 420, 360);
+D.SetBorder(10, 50, 0, 4);
+D.SetText("X-Label","Y-Label","Title");
+D.SetGridColor("#44CC44");
+D.Draw("#80FF80","#0000FF",true,"Click on me !","DiagramClick()");
+document.close();
+function DiagramClick()
+{ alert("Use your own function here."); }
+</SCRIPT> +
+
+You can use the following methods: +
    +
  • var D = new Diagram() //Constructor
  • +
  • D.SetFrame(theLeft, theTop, theRight, theBottom) //Screen
  • +
  • D.SetBorder(theLeftX, theRightX, theBottomY, theTopY) //World
  • +
  • D.SetText(theScaleX, theScaleY, theTitle) //Labels (optional)
  • +
  • D.ScreenX(theRealX) //Coordinate transformation world->screen
  • +
  • D.ScreenY(theRealY) //Coordinate transformation world->screen
  • +
  • D.RealX(theScreenX) //Coordinate transformation screen->world
  • +
  • D.RealY(theScreenY) //Coordinate transformation screen->world
  • +
  • D.GetXGrid() //returns array, which contains min, delta and max of the X grid
  • +
  • D.GetYGrid() //returns array, which contains min, delta and max of the Y grid
  • +
  • D.SetGridColor(theGridColor[, theSubGridColor]) //Colors of X and Y grid lines
  • +
  • D.SetXGridColor(theGridColor[, theSubGridColor]) //Colors of X grid lines
  • +
  • D.SetYGridColor(theGridColor[, theSubGridColor]) //Colors of Y grid lines
  • +
  • D.Draw(theDrawColor, theTextColor, isScaleText[, theTooltipText[, theOnClickAction +[, theOnMouseoverAction[, theOnMouseoutAction]]]]) //Display, +theDrawColor can be an image
  • +
  • D.SetVisibility(isVisible) //Show or Hide
  • +
  • D.SetTitle(theTitle) //TooltipText
  • +
  • D.Delete() //Delete DIV object of D from the document
  • +
  • delete D //Destructor
  • +
+Before drawing, you can set the following properties: +
    +
  • D.XScale // 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • D.YScale // 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • D.XScalePosition // "bottom" (default), "botom-left", "bottom-right", "top", "top-left", "top-right"
  • +
  • D.YScalePosition // "left" (default), "left-top", "left-bottom", "right", "right-top", "right-bottom"
  • +
  • D.XGridDelta //Grid interval in X-direction, if it is 0 (default) it will be detected automatically
  • +
  • D.YGridDelta //Grid interval in Y-direction, if it is 0 (default) it will be detected automatically
  • +
  • D.XSubGrids //Number of Sub-Grid intervals within one Grid interval in X-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • D.YSubGrids //Number of Sub-Grid intervals within one Grid interval in Y-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • D.Font //Text style, default = "font-family:Verdana;font-weight:normal;font-size:10pt;line-height:13pt;"
  • +
+After calling D.GetXGrid() / D.GetYGrid() you can read: +
    +
  • D.XGrid[0], D.XGrid[1] and D.XGrid[2] // min, delta and max of the X grid
  • +
  • D.YGrid[0], D.YGrid[1] and D.YGrid[2] // min, delta and max of the Y grid
  • +
+Because of a bug in Netscape 4.x you must add the following code in the web page
+before using the diagram objects:
+<DIV STYLE="position:absolute; top:0px"></DIV>
+Also for Netscape 4.x the file transparent.gif must be in the directory of the web page.
+
+If you want to draw the diagram into another window, you can specify the target window:
+_DiagramTarget=theTargetWindow;
+_DiagramTarget is a global variable, which is valid within the entire document.
+The default _DiagramTarget is the window object of the current document. +
+ +The Diagram in the new window was generated by:

+<SCRIPT Language="JavaScript">
+function MyXScale(nn)
+{ var tt=new Array("left", "center", "right");
+  return("<b>"+tt[nn]+"</b>");
+}
+function NewWindow()
+{ _DiagramTarget=window.open("","",
+  "width=460,height=300,menubar=no,locationbar=no,resizable=yes,status=no,scrollbars=no");
+  with (_DiagramTarget.document)
+  { open();
+    writeln("<HTML><HEAD><TITLE>Diagram in a new window</TITLE></HEAD><BODY>");
+    var D2=new Diagram();
+    D2.SetFrame(60, 40, 400, 240);
+    D2.SetBorder(0, 3, 0, 4);
+    D2.XGridDelta=1;
+    D2.XScale="function MyXScale";
+    D2.XScalePosition="top-right";
+    D2.YSubGrids=1;
+    D2.Font="font-family:Verdana;font-weight:normal;font-size:8pt;line-height:13pt;";
+    D2.SetText("","", "Diagram with small font and function-scale");
+    D2.SetGridColor("#cccccc", "#eeddcc");
+    D2.Draw("#FFEECC", "#336699", false, "Click on me !", "opener.DiagramClick()");
+    writeln("</BODY></HTML>");
+    close();
+  }
+}
+</SCRIPT> +


+ + + +
« IntroductionThe Bar object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dot_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dot_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dot_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,76 @@ + + + +JavaScript Diagram Builder - The Dot object + + + + + +
+
+

JavaScript Diagram Builder - The Dot object

+
+The Dot object is used to display a dot on the screen, especially to draw it in a diagram area. In order to +find the appropriate screen position of a dot, the diagram functions ScreenX, ScreenY, RealX and +RealY can be used. It is also possible, to move, hide and delete a dot after it has been drawn. +
+ + +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 640, 460);
+D.SetBorder(6, 18, 0, 6);
+D.XGridDelta=1;
+D.SetGridColor("#808080");
+D.Draw("#FF80FF", "#000000", false);
+var Size, Type, x;
+Color=new Array("#000000","#FF0000","#0000FF","#000000","#FF0000","#0000FF");
+for (Size=6; Size<=18; Size++)
+{ x=D.ScreenX(Size);
+  new Dot(x, D.ScreenY(0), Size, 'smile.gif', "", "Type: smile.gif, Size:"+Size);
+  for (Type=1; Type<7; Type++)
+    new Dot(x, D.ScreenY(Type), Size, Type, Color[Type-1], "Type:"+Type+", Size:"+Size);
+}
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var D = new Dot(theX, theY, theSize, theType, theColor[, theTooltipText
    +[, theOnClickAction[, theOnMouseoverAction[, theOnMouseoutAction]]]])

    //Constructor and Display, size should be 6..18, type should be 1..6 or an image
  • +
  • D.SetColor(theColor) //Color
  • +
  • D.SetVisibility(isVisible) //Show or Hide
  • +
  • D.SetTitle(theTitle) //TooltipText
  • +
  • D.MoveTo(theX, theY) //Move
  • +
  • D.Delete() //Delete DIV object of D from the document
  • +
  • delete D //Destructor
  • +

+
+ + + +
« The Box objectThe Pixel object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/download.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/download.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/download.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,26 @@ + + + +JavaScript Diagram Builder - Download + + + +
+
+

LT Diagram Builder - Download

+
+Download of v. 3.3 +

+
+ + + +
« PHP & ASPLutz Tautenhahn
© 2001-2005
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dynamic_example.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dynamic_example.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/dynamic_example.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,172 @@ + + + +JavaScript Diagram Builder - Dynamic example + + + + + + +
+
+

JavaScript Diagram Builder - Dynamic example

+
+
+ + + + + + + + + + + + + + + + +
x-min:x-max:y-min:y-max:
y=
+
+ +
+The diagram displays the function which you type into the input field in the specified +x and y interval.
+You can use the standard operators
+
++ - * / ( )
+
+the constants of the JavaScript Math object
+
+E LN2 LN10 LOG2E LOG10E PI SQRT1_2 SQRT2
+
+and the functions of the Math object
+
+abs acos asin atan ceil cos exp floor log max min pow random round +sin sqrt tan
+
+to define a function.
+
+When the page is loaded, first a new diagram object and new pixel objects are created:
+
+<SCRIPT Language="JavaScript">
+document.open();
+var D=new Diagram();
+D.SetFrame(60, 175, 635, 500);
+D.SetBorder(-1, 1, -1, 1);
+D.SetText("x","y", "y=f(x)");
+D.SetGridColor("#808080", "#CCCCCC");
+D.Draw("#DDDDDD", "#000000", true, "");
+var i, j, x, y;
+j= D.ScreenY(0);
+P=new Array(636);
+for (i=60; i<=635; i++)
+  P[i]=new Pixel(i, j, "#0000FF");
+document.close();
+</SCRIPT>
+
+After you click the "Draw" button, the properties of the already existing objects are changed, +to display the new function:
+
+<SCRIPT Language="JavaScript">
+function Draw()
+{ // ... some code was cutted here
+  D.SetBorder(xmin, xmax, ymin, ymax);
+  D.SetText("x", "y", "y="+document.inputform.fx.value);
+  D.SetGridColor("#808080", "#CCCCCC");
+  D.Draw("#DDDDDD", "#000000", true, "y="+document.inputform.fx.value);
+  var isEvalSafe=(window.EvalSafe)&&(EvalSafe("1+1")==2);
+  for (i=60; i<=635; i++)
+  { x = D.RealX(i);
+    if (isEvalSafe)
+    { y=EvalSafe(document.inputform.fx.value);
+      if (isNaN(parseInt(y)))
+      { alert(document.inputform.fx.value+" can not be evaluated for x="+x);
+        return;
+      }
+    }
+    else
+    { with (Math) y=eval(document.inputform.fx.value);
+    }
+    if ((ymin<=y)&&(y<=ymax)) P[i].MoveTo(i, D.ScreenY(y));
+    else P[i].SetVisibility(false);
+  }
+}
+</SCRIPT>
+The above example will only work correctly with IE 5.x or Netscape 6.x. However, instead of dynamically changing +the properties of the objects you can use two frames - the first for the input and the second for the diagram. +After clicking the "Draw" button the first frame writes the parameters to variables in the parent window and reloads +the second frame (use location.href=url, not history.go(0)!), which reads the variables from the parent window and +draws the diagram and function corresponding to the parameters.
+This will work with all browsers. +
+

+ + + + +
« Static ExampleIframe Example »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsafe.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsafe.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsafe.js 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,11 @@ +function EvalSafe(ss) +{ var jj=""; + if (ss.indexOf("^")>=0) return(""); + try + { with (Math) jj=eval(ss); + } + catch(error) + { return(""); + } + return(jj); +} Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsave.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsave.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/evalsave.js 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,10 @@ +function EvalSave(ss) +{ var jj=""; + try + { with (Math) jj=eval(ss); + } + catch(error) + { return(""); + } + return(jj); +} Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_display.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_display.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_display.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,41 @@ + + + +JavaScript Diagram Builder + + + + + + +
+ + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_input.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_input.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_input.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,50 @@ + + + +JavaScript Diagram Builder + + + +
+ + + + + + + + + + + + + + + + +
x-min:x-max:y-min:y-max:
y=
+
+ + + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_main.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_main.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/fx_main.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,16 @@ + + + +JavaScript Diagram Builder + + + + + + + + + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_blue.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_blue.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_green.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_green.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_orange.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_orange.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_red.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/h_red.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/iframe_example.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/iframe_example.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/iframe_example.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,55 @@ + + + +JavaScript Diagram Builder - Iframe Example + + + + + +
+ +

JavaScript Diagram Builder - Iframe Example

+By using an iframe as _DiagramTarget you can put a diagram to a relative position within a +webpage (for instance after text 1 and before text 2). With this there is no need anymore to use absolute positioned +divs to keep the text outside of the diagram area. Test it by altering the width of your window and see +how the diagram moves and does not overlap with the text. However take care: Although they belong to the +HTML 4.0 standard, iframes are by now not supported by all web browsers. +
+ + +
+This diagram was generated by
+<iframe frameborder=0 scrolling="no" width=400 height=240 name="F1"></iframe>
+<SCRIPT Language="JavaScript">
+_DiagramTarget=window.frames["F1"];
+_DiagramTarget.document.open();
+_DiagramTarget.document.writeln("<html><head></head><body bgcolor='#eeeeee'>");
+var D=new Diagram();
+D.SetFrame(70, 30, 380, 200);
+D.SetBorder(10, 50, 0, 4);
+D.SetText("X-Label","Y-Label","Title");
+D.Draw("#80FF80","#0000FF",true,"Click on me !","parent.F1DiagramClick()");
+_DiagramTarget.document.writeln("</body></html>");
+_DiagramTarget.document.close();
+function F1DiagramClick(){ alert("Use your own function here."); }
+</SCRIPT>
+
+ + + +
« Dynamic ExampleRelative Position »
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/index.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/index.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/index.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,26 @@ + + + +JavaScript Diagram Builder + + + + + + + + + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/introduction.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/introduction.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/introduction.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,54 @@ + + + +JavaScript Diagram Builder - Introduction + + + +
+
+

JavaScript Diagram Builder - Introduction

+
+The JavaScript Diagram Builder v. 3.3 is a library of some objects and functions, which can help you to display +a coordinate diagram (resp. a chart or graph) in your webpage in an easy way. The file 'diagram.js' contains all the necessary objects and functions. +This file must be included in the header of your webpage:

+<SCRIPT Language="JavaScript" src="diagram.js"></SCRIPT>

+The script will best work with Microsoft Internet Explorer 5.x, Netscape 6.x, Opera 7.x or Konqueror 3.x under Windows and +Linux, but it will also work with Netscape 4.x and Opera 5.x under Windows and Linux with some restrictions.

+The JavaScript Diagram Builder is especially useful, if you want to display a coordinate diagram (chart or graph) which depends +on the client's input parameter or from data of a database.
+
+The JavaScript Diagram Builder v. 3.3 is copyrighted freeware. It is provided "as is", without a warranty of any kind. +If you encounter any bugs, or if you have any suggestions for further versions, then send me an email.
+
+Here is the history of new features:
    +
  • object 'Line' and object 'Area' available (v. 2.4)
  • +
  • draw scale with unit (v. 2.4)
  • +
  • define target window for the diagram (v. 2.4)
  • +
  • get grid values without drawing the diagram (v. 2.4)
  • +
  • scale text can be defined as function of scale values (v. 2.5)
  • +
  • grid lines can be drawn (v. 2.5)
  • +
  • scale interval (and consequently number of scale lines) can be defined (v. 2.5)
  • +
  • font can be changed for diagram scale, Bar- and Box-objects (v. 2.5)
  • +
  • sub-grid lines can be drawn (v. 2.6)
  • +
  • the code is conform with XHTML 1.0 standard (v. 2.7)
  • +
  • method SetColor available for all objects (v. 2.8)
  • +
  • script file is splitted into browser specific parts (v. 2.8)
  • +
  • object 'Arrow' available (v. 2.9)
  • +
  • image can be used as type of a 'Dot' object (v. 2.9)
  • +
  • PHP and ASP versions of the script available! (v. 3.0)
  • +
  • method of Diagram object 'SetGridColor' should be used for compatibility (v. 3.0)
  • +
  • method of Diagram object 'SetGridColor' should be used for compatibility (v. 3.0)
  • +
  • grid color and scale position for X and Y can be specified (v. 3.1)
  • +
  • image can be used for theDrawColor of Diagram object and Text of Bar/Box (v. 3.1)
  • +
  • logarithmic scale can be drawn (v. 3.2)
  • +
  • object 'Pie' available, onMouseOver and onMouseOut can be used (v. 3.3)
  • +
+

+
+ + + +
Lutz Tautenhahn
© 2001-2005
The Diagram object »
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/line_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/line_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/line_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,90 @@ + + + +JavaScript Diagram Builder - The Line object + + + + + +
+
+

JavaScript Diagram Builder - The Line object

+
+The Line object is used to display a line on the screen, especially to draw it in a diagram area. It is +possible to hide, move and delete a line after it has been drawn. Unlike in older versions, the images +o_rrggbb.gif are no longer required to draw Line objects. +
+ + +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+function Fahrenheit(vv){ return("<nobr>"+Math.round(vv*18+320)/10+"� F</nobr>"); }
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 520, 360);
+D.SetBorder(6, 18, 20, 30);
+D.SetText("","", "temperature measured during the day");
+D.XScale=" h";
+D.YScale="� C";
+D.SetGridColor("#cccccc");
+D.Draw("#FFEECC", "#663300", false);
+var t, T0, T1;
+D.GetYGrid();
+_BFont="font-family:Verdana;font-size:10pt;line-height:13pt;";
+for (t=D.YGrid[0]; t<=D.YGrid[2]; t+=D.YGrid[1])
+  new Bar(D.right+6, D.ScreenY(t)-8, D.right+6, D.ScreenY(t)+8, "", Fahrenheit(t), "#663300");
+T1=22;
+for (t=6; t<18; t++)
+{ T0=T1;
+  T1=23-4*Math.cos(t/4)+Math.random();
+  new Line(D.ScreenX(t), D.ScreenY(T0), D.ScreenX(t+1), D.ScreenY(T1), "#cc9966", 2, "temperature");
+}
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var L = new Line(theX0, theY0, theX1, theY1, theColor[, theSize[, theTooltipText[,
    +theOnClickAction [, theOnMouseoverAction[, theOnMouseoutAction]]]]])
    +//Constructor and Display
  • +
  • L.SetColor(theColor) //Color
  • +
  • L.SetVisibility(isVisible) //Show or Hide
  • +
  • L.SetTitle(theTitle) //TooltipText
  • +
  • L.MoveTo(theLeft, theTop) //Move
  • +
  • L.ResizeTo(theX0, theY0, theX1, theY1) //Resize
  • +
  • L.Delete() //Delete DIV object of L from the document
  • +
  • delete L //Destructor
  • +

+
+ + + +
« The Pixel objectThe Area object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_display.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_display.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_display.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,75 @@ + + + +JavaScript Diagram Builder + + + + + + +
+ + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_input.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_input.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_input.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,32 @@ + + + +JavaScript Diagram Builder + + + +
+ + + + + + + +
x:y:
+
+ + + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_main.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_main.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/linreg_main.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,17 @@ + + + +JavaScript Diagram Builder - Linear Regression Example + + + + + + + + + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/logarithmic_scale.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/logarithmic_scale.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/logarithmic_scale.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,87 @@ + + + +JavaScript Diagram Builder - Logarithmic Example + + + + + +
+
+

JavaScript Diagram Builder - Logarithmic Scale Example

+
+To draw a coordinate diagram with a logarithmic scale, define a function-scale (like shown in the example below) +and use GridDelta=1 (increasing values) +or GridDelta=-1 (decreasing values) and use SubGrids=-1 to get a logatithmic sub-grid. Use the logarithmic values in the +functions SetBorder and ScreenX or ScreenY, as it is shown below. +
+ +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+Hosts=new Array(28174, 80000, 290000, 500000, 727000, 1200000, 2217000, 4852000, 9472000,
+16146000, 29670000, 43230000, 72398092, 109574429, 147344723);
+function LogScale(vv)
+{ if ((vv>3)||(vv<-3)) return("10<sup>"+vv+"</sup>");
+  if (vv>=0) return(Math.round(Math.exp(vv*Math.LN10)));
+  else return(1/Math.round(Math.exp(-vv*Math.LN10)));
+}
+document.open();
+var D=new Diagram();
+D.SetFrame(100, 140, 580, 460);
+D.SetBorder(1988, 2002, Math.log(Hosts[0])/Math.LN10, Math.log(Hosts[14])/Math.LN10);
+D.SetText("Year", "Hosts", "<B>Internet growth</B>");
+D.XGridDelta=2;
+D.XSubGrids=2;
+D.YGridDelta=1;
+D.YSubGrids=-1;
+D.YScale="function LogScale";
+D.SetGridColor("#FFFFFF", "#EEEEEE");
+D.Draw("#DDDDDD", "#000000", true);
+for (var n=1; n<Hosts.length; n++)
+{ new Line(D.ScreenX(1987+n), D.ScreenY(Math.log(Hosts[n-1])/Math.LN10),
+           D.ScreenX(1988+n), D.ScreenY(Math.log(Hosts[n])/Math.LN10), "#0000ff", 2, "internet hosts");
+}
+for (n=0; n<Hosts.length; n++)
+{ new Dot(D.ScreenX(1988+n), D.ScreenY(Math.log(Hosts[n])/Math.LN10), 10, 1, "#ff0000",
+          eval(1988+n)+": "+Hosts[n]+" hosts");
+}
+document.close();
+</SCRIPT> +

+
+ + + +
« Relative PositionBrowser Support »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/menu.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/menu.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/menu.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,38 @@ + + + +JavaScript Diagram Builder - Menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

JavaScript Diagram Builder 3.3


Introduction

The Diagram object
The Bar object
The Box object
The Dot object
The Pixel object
The Line object
The Area object
The Arrow object
The Pie object

Static example
Dynamic example
Iframe example
Relative position
Logarithmic scale

Browser support

PHP & ASP

Download

Lutz Tautenhahn
© 2001-2005
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_000000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_000000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_0000ff.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_0000ff.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_ff0000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/o_ff0000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_000000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_000000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_0000ff.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_0000ff.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_ff0000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/p_ff0000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,13 @@ + + + +JavaScript Diagram Builder - PHP & ASP + + + + + + + + + Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_menu.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_menu.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_menu.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,42 @@ + + + +JavaScript Diagram Builder - PHP and ASP Menu + + + + + + + +
« Browser Support + +Download »
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_versions.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_versions.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/php_and_asp_versions.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,217 @@ + + + +JavaScript Diagram Builder - PHP & ASP versions + + + +
+

LT Diagram Builder - PHP & ASP versions

+
+Since version 3.0 you can generate images of coordinate diagrams (resp. charts or graphs) at serverside (using PHP or ASP) +and save it as file or send it back as a stream. These 2 versions are independent from the clientside JavaScript version +of the script. The method calls of the 2 scripts are very similar to the method calls of the JavaScript version. +However, the methods for changing the properties of objects (MoveTo, ResizeTo, SetColor, etc.) are not available, +because it is not possible to change these properties after the image has been created. Because of this, the bar, box, dot, +pixel, line, area, arrow and pie objects in the JavaScript version, are methods of the diagram object in the PHP and ASP version. +The usage of the script versions is shown in the following table:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Include the script file
JavaScript<SCRIPT Language="JavaScript" src="diagram.js"></SCRIPT>
PHPinclude ("diagram.php");
ASP<!--#include file="diagram.asp"-->
Generate a new diagram
JavaScript +//_DiagramTarget=window; //only necessary, if the target is not the current window
+D=new Diagram();
PHP$D=new Diagram();
+$D->Img=@ImageCreate(480, 320) or die("Cannot create a new GD image.");
+ImageColorAllocate($D->Img, 255, 255, 255); //background color
ASP +Set D=New Diagram
+Set D.Img=CreateObject("gdImage.Images.1")
+D.Img.ImageCreate 480, 320
+D.Img.ImageColorAllocate 0,255,255,255 'Background Color +
Add a bar, box, dot, etc...
JavaScript +new Bar(10, 20, 80, 40, "#ff0000", "This is Text", "#000000", "This is TooltipText", "alert(\"This is onClick event.\")");
PHP +$D->Bar(10, 20, 80, 40, "#ff0000", "This is Text", "#000000", "This is TooltipText", "alert(\"This is onClick event.\")");
ASP +D.Bar 10, 20, 80, 40, "#ff0000", "This is Text", "#000000", "This is TooltipText", "alert(""This is onClick event."")"
Save the image as file
JavaScript//not available and not necessary
PHP +ImagePng($D->Img, "my_image.png");
+ImageDestroy($D->Img);
ASP +D.Img.ImagePng 0, Server.mappath("my_image.png")
+D.Img.ImageDestroy 0
+Set D.Img=Nothing
Send the image from the server back to the client as a stream
JavaScript//not available and not necessary
PHP +header("Content-type: image/png");
+ImagePng($D->Img);
+ImageDestroy($D->Img);
ASP +'There is no direct support but you can get it working this way:
+Set objFS=Server.CreateObject("Scripting.FileSystemObject")
+FN = objFS.GetTempName()
+FN=Server.mappath(FN)
+D.Img.ImagePng 0, FN
+Set objStream = Server.CreateObject("ADODB.Stream")
+objStream.Charset = "x-ansi"
+objStream.Type = 2
+objStream.Open
+objStream.LoadFromFile FN
+Response.ContentType = "image/png"
+Response.AddHeader "Content-Disposition","filename=image.png"
+objStream.Position = 0
+objStream.Type = 1
+Response.BinaryWrite objStream.Read()
+objStream.Close
+Set objStream = Nothing
+objFS.DeleteFile FN, false
+Set objFS=Nothing
+D.Img.ImageDestroy 0
+Set D.Img=Nothing
+ +

Differences between JavaScript version and +PHP/ASP version

+In JavaScript you can use code like
+ +D.Font="font-family:Verdana;font-weight:normal;font-size:10pt;line-height:13pt;";
+_BFont="font-family:Verdana;font-weight:bold;font-size:10pt;line-height:13pt;";
+
+to set the font for the Diagram object or the Bar/Box object.
+In PHP (ASP) you will use code like
+$D->Font=4; D.Font=4
+$D->BFont=5; D.BFont=5
+to set the font(1..5) for the Diagram object or the Bar/Box object.
+You can set the font of the bar and box object BFont to -1..-5 for vertical text.
+For vertical text of the X-axis use a Font value from -1..-5.
+
+In JavaScript you can use the result of the predefined JavaScript function
+Date.UTC(2001,0,1,0,0,0); //date/time: year, month(0..11), day, hour, min, sec
+as argument for the SetBorder method of a diagram with date/time scale.
+In PHP (ASP) you can use the function
+UTC(2001,1,1,0,0,0); UTC(2001,1,1,0,0,0) //date/time: year, month(1..12), day, hour, min, sec
+which is defined in the script file diagram.php diagram.asp.
+Take care with the difference in the argument for the month! + +
+

PHP version

+You can use the following methods: +
    +
  • $D=new Diagram() //Constructor
  • +
  • $D->SetFrame($theLeft, $theTop, $theRight, $theBottom) //Screen
  • +
  • $D->SetBorder($theLeftX, $theRightX, $theBottomY, $theTopY) //World
  • +
  • $D->SetText($theScaleX, $theScaleY, $theTitle) //Labels (optional)
  • +
  • $D->ScreenX($theRealX) //Coordinate transformation world->screen
  • +
  • $D->ScreenY($theRealY) //Coordinate transformation world->screen
  • +
  • $D->RealX($theScreenX) //Coordinate transformation screen->world
  • +
  • $D->RealY($theScreenY) //Coordinate transformation screen->world
  • +
  • $D->GetXGrid() //returns array, which contains min, delta and max of the X grid
  • +
  • $D->GetYGrid() //returns array, which contains min, delta and max of the Y grid
  • +
  • $D->SetGridColor($theGridColor[, $theSubGridColor]) //Colors of X and Y grid lines
  • +
  • $D->SetXGridColor($theGridColor[, $theSubGridColor]) //Colors of X grid lines
  • +
  • $D->SetYGridColor($theGridColor[, $theSubGridColor]) //Colors of Y grid lines
  • +
  • $D->Draw($theDrawColor, $theTextColor, $isScaleText[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]) //Display
  • +
+Before drawing, you can set the following properties: +
    +
  • $D->XScale // 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • $D->YScale // 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • $D->XScalePosition // "bottom" (default), "botom-left", "bottom-right", "top", "top-left", "top-right"
  • +
  • $D->YScalePosition // "left" (default), "left-top", "left-bottom", "right", "right-top", "right-bottom"
  • +
  • $D->XGridDelta //Grid interval in X-direction, if it is 0 (default) it will be detected automatically
  • +
  • $D->YGridDelta //Grid interval in Y-direction, if it is 0 (default) it will be detected automatically
  • +
  • $D->XSubGrids //Number of Sub-Grid intervals within one Grid interval in X-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • $D->YSubGrids //Number of Sub-Grid intervals within one Grid interval in Y-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • $D->Font //Text style for scale text (1..5), default=4
  • +
  • $D->BFont //Text style for bar and box text (1..5), default=5
  • +
+After calling $D->GetXGrid() / $D->GetYGrid() you can read: +
    +
  • $D->XGrid[0], $D->XGrid[1] and $D->XGrid[2] // min, delta and max of the X grid
  • +
  • $D->YGrid[0], $D->YGrid[1] and $D->YGrid[2] // min, delta and max of the Y grid
  • +
+For the display of data you can use the following methods: +
    +
  • $D->Bar($theLeft, $theTop, $theRight, $theBottom, $theDrawColor[, $theText[, $theTextColor[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]]])
  • +
  • $D->Box($theLeft, $theTop, $theRight, $theBottom, $theDrawColor[, $theText[, $theTextColor[, $theBorderWidth[, $theBorderColor[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]]]]])
  • +
  • $D->Dot($theX, $theY, $theSize, $theType, $theColor[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]])
  • +
  • $D->Pixel($theX, $theY, $theColor)
  • +
  • $D->Line($theX0, $theY0, $theX1, $theY1, $theColor[, $theSize[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]])
  • +
  • $D->Area($theX0, $theY0, $theX1, $theY1, $theColor[, $theBase[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]])
  • +
  • $D->Arrow($theX0, $theY0, $theX1, $theY1, $theColor[, $theSize[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]]])
  • +
  • $D->Pie($theXCenter, $theYCenter, $theOffset, $theRadius, $theAngle0, $theAngle1, $theColor[, $theTooltipText[, $theOnClickAction[, $theOnMouseoverAction[, $theOnMouseoutAction]]]])
  • +
+ +
+

ASP version - VBScript language

+You can use the following methods: +
    +
  • D=New Diagram 'Constructor
  • +
  • D.SetFrame theLeft, theTop, theRight, theBottom 'Screen
  • +
  • D.SetBorder theLeftX, theRightX, theBottomY, theTopY 'World
  • +
  • D.SetText theScaleX, theScaleY, theTitle 'Labels (optional)
  • +
  • D.ScreenX(theRealX) 'Coordinate transformation world->screen
  • +
  • D.ScreenY(theRealY) 'Coordinate transformation world->screen
  • +
  • D.RealX(theScreenX) 'Coordinate transformation screen->world
  • +
  • D.RealY(theScreenY) 'Coordinate transformation screen->world
  • +
  • D.GetXGrid 'returns array, which contains min, delta and max of the X grid
  • +
  • D.GetYGrid 'returns array, which contains min, delta and max of the Y grid
  • +
  • D.SetGridColor theGridColor, theSubGridColor 'Colors of X and Y grid lines
  • +
  • D.SetXGridColor theGridColor, theSubGridColor 'Colors of X grid lines
  • +
  • D.SetYGridColor theGridColor, theSubGridColor 'Colors of Y grid lines
  • +
  • D.Draw theDrawColor, theTextColor, isScaleText, theTooltipText, theEventActions 'Display
  • +
+Before drawing, you can set the following properties: +
    +
  • D.XScale ' 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • D.YScale ' 0 = no scale; 1 = numeric (default); 2, 3, ... = date/time; string = numeric+unit +
    "function FunctionName" = FunctionName(ScaleValue)
  • +
  • D.XScalePosition // "bottom" (default), "botom-left", "bottom-right", "top", "top-left", "top-right"
  • +
  • D.YScalePosition // "left" (default), "left-top", "left-bottom", "right", "right-top", "right-bottom"
  • +
  • D.XGridDelta 'Grid interval in X-direction, if it is 0 (default) it will be detected automatically
  • +
  • D.YGridDelta 'Grid interval in Y-direction, if it is 0 (default) it will be detected automatically
  • +
  • D.XSubGrids 'Number of Sub-Grid intervals within one Grid interval in X-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • D.YSubGrids 'Number of Sub-Grid intervals within one Grid interval in Y-direction, if it is 0 (default) it will be detected automatically, if it is -1 then a logarithmic Sub-Grid will be drawn
  • +
  • D.Font 'Text style for scale text (1..5), default=4
  • +
  • D.BFont 'Text style bar and box text (1..5), default=5
  • +
+After calling D.GetXGrid / D.GetYGrid you can read: +
    +
  • D.XGrid(0), D.XGrid(1) and D.XGrid(2) ' min, delta and max of the X grid
  • +
  • D.YGrid(0), D.YGrid(1) and D.YGrid(2) ' min, delta and max of the Y grid
  • +
+For the display of data you can use the following methods: +
    +
  • D.Bar theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theTooltipText, theEventActions
  • +
  • D.Box theLeft, theTop, theRight, theBottom, theDrawColor, theText, theTextColor, theBorderWidth, theBorderColor, theTooltipText, theEventActions
  • +
  • D.Dot theX, theY, theSize, theType, theColor, theTooltipText, theEventActions
  • +
  • D.Pixel theX, theY, theColor
  • +
  • D.Line theX0, theY0, theX1, theY1, theColor, theSize, theTooltipText, theEventActions
  • +
  • D.Area theX0, theY0, theX1, theY1, theColor, theBase, theTooltipText, theEventActions
  • +
  • D.Arrow theX0, theY0, theX1, theY1, theColor, theSize, theTooltipText, theEventActions
  • +
  • D.Pie theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1, theColor, theTooltipText, theEventActions
  • +
+For theEventActions use either theOnClickAction or
+Array(theOnClickAction, theOnMouseoverAction, theOnMouseoutAction)
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pi.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pi.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pie_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pie_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pie_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,69 @@ + + + +JavaScript Diagram Builder - The Pie object + + + + + +
+
+

JavaScript Diagram Builder - The Pie object

+
+The Pie object is used to display an filled arc on the screen. It is possible to hide, move and delete it after +it has been drawn. +
+ + +
+This diagram was generated by
+<SCRIPT Language="JavaScript">
+P=new Array();
+document.open();
+P[0]=new Pie(100,240,10,80,0*3.6,10*3.6,"#ff6060");
+P[1]=new Pie(100,240,0,80,10*3.6,40*3.6,"#ffa000");
+P[2]=new Pie(100,240,0,80,40*3.6,100*3.6,"#f6f600");
+new Bar(200,190,280,210,"#ff6060","Apples","#000000","", "void(0)","MouseOver(0)","MouseOut(0)");
+new Bar(200,230,280,250,"#ffa000","Oranges","#000000","", "void(0)","MouseOver(1)","MouseOut(1)");
+new Bar(200,270,280,290,"#f6f600","Bananas","#000000","", "void(0)","MouseOver(2)","MouseOut(2)");
+document.close();
+function MouseOver(i) { P[i].MoveTo("","",10); }
+function MouseOut(i) { P[i].MoveTo("","",0); }
+</SCRIPT> +
+
+

+You can use the following methods: +
    +
  • var P = new Pie(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1, theColor[,
    +theTooltipText[, theOnClickAction[, theOnMouseoverAction[, theOnMouseoutAction]]]])

    +//Constructor and Display
  • +
  • P.SetColor(theColor) //Color
  • +
  • P.SetVisibility(isVisible) //Show or Hide
  • +
  • P.SetTitle(theTitle) //TooltipText
  • +
  • P.MoveTo(theXCenter, theYCenter, theOffset) //Move
  • +
  • P.ResizeTo(theXCenter, theYCenter, theOffset, theRadius, theAngle0, theAngle1) //Resize
  • +
  • P.Delete() //Delete DIV object of P from the document
  • +
  • delete P //Destructor
  • +

+
+ + + +
« The Arrow objectStatic example »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pixel_object.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pixel_object.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/pixel_object.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,102 @@ + + + +JavaScript Diagram Builder - The Pixel object + + + + + +
+
+

JavaScript Diagram Builder - The Pixel object

+
+The Pixel object is used to display a pixel on the screen, especially to draw it in a diagram area. In order to +find the appropriate screen position of a pixel, the diagram functions ScreenX, ScreenY, RealX and +RealY can be used. It is also possible, to move, hide and delete a pixel after it has been drawn. Take care +not to draw too many pixels, because this will slow down your webpage. +
+ +
+This diagram was generated by

+<SCRIPT Language="JavaScript">
+function MyXScale(xx)
+{ var vv=Math.round(xx*4/Math.PI);
+  if (vv==0) return(0);
+  if (vv==4) return("<img src=\"pi.gif\">");
+  if (vv==8) return("2 <img src=\"pi.gif\">");
+  if (vv%2==0) return(eval(vv/2)+"/2 <img src=\"pi.gif\">");
+  return(vv+"/4 <img src=\"pi.gif\">");
+}
+document.open();
+var D=new Diagram();
+D.SetFrame(80, 160, 540, 460);
+D.SetBorder(0, eval(2*Math.PI), -1, 1);
+D.SetText("", "", "<B>some functions</B>");
+D.XGridDelta=Math.PI/4;
+D.XScale="function MyXScale";
+D.YGridDelta=0.2;
+D.YSubGrids=2;
+D.SetGridColor("#FFFFFF", "#EEEEEE");
+D.Draw("#DDDDDD", "#000000", false);
+var i, j, x;
+for (i=80; i<=540; i++)
+{ x = D.RealX(i);
+  j= D.ScreenY(Math.sin(x));
+  new Pixel(i, j, "#FF0000");
+  j= D.ScreenY(Math.cos(x));
+  new Pixel(i, j, "#0000FF");
+}
+new Bar(560, 200, 680, 220, "#0000FF", "f(x)=cos(x)", "#FFFFFF");
+new Bar(560, 260, 680, 280, "#FF0000", "f(x)=sin(x)", "#000000");
+document.close();
+</SCRIPT> +

+You can use the following methods: +
    +
  • var P = new Pixel(theX, theY, theColor) //Constructor and Display
  • +
  • P.SetColor(theColor) //Color
  • +
  • P.SetVisibility(isVisible) //Show or Hide
  • +
  • P.MoveTo(theX, theY) //Move
  • +
  • P.Delete() //Delete DIV object of P from the document
  • +
  • delete P //Destructor
  • +

+
+ + + +
« The Dot objectThe Line object »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_000000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_000000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_0000ff.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_0000ff.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_ff0000.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/q_ff0000.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/relative_position.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/relative_position.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/relative_position.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,50 @@ + + + +JavaScript Diagram Builder - Relative Positionierung + + + + + +
+ +

JavaScript Diagram Builder - Relative Position

+By including the diagram code between <div style='position:relative; top:0px; height:220px'> and </div> +you can put a diagram to a relative position in a web page also without using of iframes (for instance after text 1 and before text 2). +The values for the vertical positions of the diagram objects are with regard to the covering div. Instead of height:220px +you should use the height, which is required by the diagram. In this way diagrams can be inserted directly between text blocks +of a web page. Test it by altering the width of your window and see how the diagram moves and does not overlap with the text. +This method does not work with the old browser Netscape 4.7, which however is almost no more used. +
+
+ +
+
+This diagram was generated by
+<div style='position:relative; top:0px; height:220px'>
+<SCRIPT Language="JavaScript">
+var D=new Diagram();
+D.SetFrame(70, 30, 380, 200);
+D.SetBorder(10, 50, 0, 4);
+D.Draw("#80FF80","#0000FF",false);
+for (var i=15; i<50; i+=5)
+  new Bar(D.ScreenX(i)-10, D.ScreenY(i%3+1), D.ScreenX(i)+10, D.ScreenY(0), "#00cccc");
+</SCRIPT>
+</div>
+
+ + + +
« Dynamic ExampleLogarithmic Scale Example »
+ + + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/showline.htm =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/showline.htm,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/showline.htm 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,54 @@ + + + + + + + + +
+
+Apples +Oranges +Bananas +
+ + + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/smile.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/smile.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/static_example.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/static_example.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/static_example.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,171 @@ + + + +JavaScript Diagram Builder - Static example + + + + + +
+
+

JavaScript Diagram Builder - Static Example

+
+The diagrams on this page are static in a sense, that after the objects are created, they are never changed. +Here are shown several date scales, which can be in the range from seconds up to years. +Unfortunately, there are many different date formats in the world (for instance day.month, day-month, +month/day). If you want to use another date format, then you can add it to the function _DateFormat() +in the file 'diagram.js'. +
+ +
+Code example for a diagram with date scale:

+<SCRIPT Language="JavaScript">
+D=new Diagram();
+...
+D.SetBorder(
+Date.UTC(2001,0,1,0,0,0), //date/time (left): year, month(0..11), day, hour, min, sec
+Date.UTC(2001,11,31,23,59,59), //date/time (right): year, month(0..11), day, hour, min, sec
+0, 1); //any y scale
+//change the scale type from default=1 into 2 or higher before drawing:
+D.XScale=2; //2,3,4=predefined date scales; 5,6,..=userdefined date scales
+...
+//get the screen position of a date/time for the display of bars, dots or pixels:
+var x=D.ScreenX(Date.UTC(2001,10,11,11,11,0));
+...
+</SCRIPT>
+
+ + + +
« The Pie objectDynamic Example »
+
+ + \ No newline at end of file Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/transparent.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/transparent.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_blue.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_blue.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_green.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_green.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_orange.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_orange.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_red.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/v_red.gif,v diff -u Binary files differ Index: openacs-4/packages/xotcl-request-monitor/www/resources/diagram/zoom_line.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-request-monitor/www/resources/diagram/zoom_line.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-request-monitor/www/resources/diagram/zoom_line.html 14 Dec 2005 16:09:03 -0000 1.1 @@ -0,0 +1,87 @@ + + + +JavaScript Diagram Builder - The Line object + + + + + +
+ + + + \ No newline at end of file