Опис інтерфейсу створення екземпляру анкети.
Спочатку обираємо у випадаючому списку завдання «Опитувальник».
Отримуємо наступне діалогове вікно:
Діалогове вікно редагування індентифікації екземпляру анкети.

Тут ми задаємо назву анкети та її короткий опис. Наступний крок – це встановлення строку існування анкети. Use Close Date – це дата коли екземпляр анкети буде блоковано для користування.
Наступна частина першого вікна редагування(параметри анкети).

Тип респонденту – параметр, що дозволяє анкетуватися як відкрито, так і анонімно.
Respondent Eligibility – які групи можуть анкетуватися.
View responses – групи, що можуть проглядати результати.
Questionnaire Type – обираємо Private або Public.
Save/Resume answers - Надає можливість зберігати відповіді і продовжети проходження анкети у будь-який зручний час.
Наступне діалогове вікно редагування анкети(оформлення).

Заповнюємо поля оформення анкети. У графу Confirmation Page вводимо адрусу-посилання, куди необхідно повернутися після закінчення анкетування.
Кнопка Edit Questions – перехід до вікна редагування змісту питань анкети.
Кнопка Reorder Questions – перехід до вікна редагування позиції питань.

Finish - Закінчення створення екземпляру анкети.
Редагування змісту анкети.
Вікно виглядає так:

Question Text – тут через клавішу Enter вводимо(вважаючи специфіку анкети) два вирази, що формують питання. Далі з випадаючого списку Type обираємо, створений нами новий тип відповіді four scroll. Спираючись на специфіку анкети, заповнюємо чотири варіанти відповіді в наступному порядку: A, C, B ,D.
Приклад виконання програми.

Загальні коментарі
Для реалізації поставленої задачі було взято найновішу версію модуля questionnaire для версії 1.8 і доповнено її новим типом питань – з чотирма скролами.
Структура БД
Модуль questionnaire використовує такі таблиці:
mdl_questionnaire – інформанія про опитувальники
mdl_questionnaire_attempts – інформація про спроби
mdl_questionnaire_question – інформація про питання
mdl_questionnaire_question_choice – варіанти відповідей до питань
mdl_questionnaire_question_type – типи питань (додали свій тип 4 Scrolls)
mdl_questionnaire_response – записи про відповіді
mdl_questionnaire_response_bool – самі відповіді на питання булівського типу
mdl_questionnaire_response_date – відповді на питання типу «дата»
mdl_questionnaire_response_multiple – відповіді на питання з декількома опціями
mdl_questionnaire_response_other – відповіді на інші питання
mdl_questionnaire_response_rank – відповіді на питання типу «ранг»
mdl_questionnaire_response_scrolls – відповіді на питання типу 4 Scrolls
mdl_questionnaire_response_single – відповіді на питання, які вимагають однієї відповіді
mdl_questionnaire_response_text – відповіді на питання, які вимагають текстовоі відповіді
mdl_questionnaire_survey – інформація про самі анкети
Фактично, робота нашого доповнення базується на таблицях:
mdl_questionnaire_response_scrolls
mdl_questionnaire_response
Код програми
Практично вся робота модуля виконується в двох файлах:
locallib.php – опис загального класу опитувальника, виводу результатів, контролю, хто може проходити і скільки разі і т. ін.
questiontypes/questiontypes. class – опис типів питань, як вони виводять, яким чином зберігаються дані для кожного питання та як вони аналізуються.
В першому файлі було внесено такі зміни:
1. Додано функцію, яка видаляє пусті значення з масиву (буде використовуватися при виводу питання
/**
* Clears array from empty values
*
* @param array $arr Array to be cleared
* @return array
*/
function clear_array($arr)
{
if (!is_array($arr) || sizeof($arr) < 1) return $arr;
foreach ($arr as $key => $val)
{
if (empty($val)) unset($arr[$key]);
}
return array_merge($arr, array());
}
2. На строках 202-217 код змінено для того, щоб всі користувачі могли дивитися свої результати:
if (isteacher($this->course->id) || $this->has_4scrolls()) {
echo '<td align="right" valign="middle">';
if ($numresp = $this->count_submissions($USER->id)) {
$strviewresponses = get_string('viewyourresponses', 'questionnaire', $numresp);
echo '<span class="returnLink"><a href="myreport. php? instance='.$this->id.
'&user='.$USER->id.'">'.$strviewresponses.'</a></span> ';
}
if ($this->is_survey_owner() && isteacher($this->course->id)) {
if ($numresp = $this->count_submissions()) {
$strviewresponses = get_string('viewresponses', 'questionnaire', $numresp);
echo '<span class="returnLink"><a href="report. php? instance='.$this->id.
'&sid='.$this->sid.'&qact=vresp">'.$strviewresponses.'</a></span>';
} else {
echo get_string('noresponses', 'questionnaire');
}
}
3. На строках 303-342 код змінено для того, щоб виводити результати опитування.
Тут за допомогою метода has_4scrolls() перевіряється, чи є в поточному опитувальнику питання з кривої акцентів. Якщо так – то обробляємо як криву акцентів. Якщо ні – то обробляємо як звичайний опитувальник
if (!$this->has_4scrolls())
{
switch ($this->qtype) {
case QUESTIONNAIREDAILY:
$msgstring = ' '.get_string('today', 'questionnaire');
break;
case QUESTIONNAIREWEEKLY:
$msgstring = ' '.get_string('thisweek', 'questionnaire');
break;
case QUESTIONNAIREMONTHLY:
$msgstring = ' '.get_string('thismonth', 'questionnaire');
break;
default:
$msgstring = '';
break;
}
echo ('<div class="message">'.get_string("alreadyfilled", "questionnaire", $msgstring).'</div>');
}
else
{
//get response id's user filled in
$rids = $this->get_rid_by_uid($USER->id);
if (is_array($rids))
{
echo '<br /><br /><br /><br />';
print_simple_box_start('center', '95%');
echo '<center><strong>Результати</strong>:<br />';
$captions = array('Зараз', 'Бажано', 'Перспектива');
$ridsNum = sizeof($rids);
//cycle through all of them and output a graph
for ($i = 0; $i < $ridsNum; $i++)
{
echo '<span>'.$captions[$i].'</span><br />';
$this->display_accent_curve_results($rids[$i]);
echo '<br /><br />';
}
echo '</center>';
print_simple_box_end();
}
}
4. В метод view_response() внесено аналогічні зміни (строки 362-393)
if (!$this->has_4scrolls())//if it is a regular survey
{
$this->print_survey_start('', 1, 1, 0, $rid);// JR
$data = new Object();
$i = 1;
echo '<div class="mainTable">';
if (!$blankquestionnaire) {
$this->response_import_all($rid, $data);
}
foreach ($this->questions as $question) {
if ($question->type_id < QUESPAGEBREAK) {
$question->response_display($data, $i++);
}
}
echo '</div>';
$this->print_survey_end(1, 1);
}
else //if it is an accent curve questionnaire
{
$data = $this->analyse_responses($rid);
foreach ($data as $key => $arr)
{
foreach ($arr as $sector => $value)
{
$dataStr[] = $key.$sector.'='.$value;
}
}
$dataStr = implode('&', $dataStr);
echo '<img src="graph. php?'.$dataStr.'" />';
}
5. В метод view_all_responses внесено зміни, щоб виводились всі відповіді (строки 410-470)
/**
* Added by Stepan
*/
if ($this->has_4scrolls())
{
//get response id's user filled in
if (is_array($resps))
{
echo '<center><strong>Результати</strong>:<br />';
$captions = array('Зараз', 'Бажано', 'Перспектива');
$respsNum = sizeof($resps);
//cycle through all of them and output a graph
$i = 0;
foreach ($resps as $rid => $_)
{
echo '<span>'.$captions[$i].'</span><br />';
$this->display_accent_curve_results($rid);
echo '<br /><br />';
$i++;
$rids[] = $rid;
}
if (sizeof($rids) == 3)
{
echo '<span>Еволюція поглядів</span><br />';
$this->display_accent_curve_user_desire($rids);
}
echo '</center>';
}
}
else
{
$this->print_survey_start('', 1, 1, 0);
foreach ($resps as $resp) {
$data[$resp->id] = new Object();
$this->response_import_all($resp->id, $data[$resp->id]);
}
$i = 1;
echo '<div class="mainTable">';
foreach ($this->questions as $question) {
if ($question->type_id < QUESPAGEBREAK) {
$method = $QTYPENAMES[$question->type_id].'_response_display';
if (method_exists($question, $method)) {
$question->questionstart_survey_display($i);
foreach ($data as $respid => $respdata) {
echo '<div class="respdate">'.userdate($resps[$respid]->submitted).'</div>';
$question->$method($respdata);
echo '<hr />';
}
$question->questionend_survey_display($i);
} else {
error(get_string('displaymethod', 'questionnaire'));
}
$i++;
}
}
echo '</div>';
$this->print_survey_end(1, 1);
}
6. В метод user_can_take внесені зміни, щоб виясняти, скільки разів користувач вже проходив тестування (строки 494-516)
/**
* Modified by Stepan.
* In original this brunch returned TRUE
*/
if ($this->has_4scrolls())
{
$sql = 'SELECT count(*) Attempts
FROM mdl_questionnaire_attempts a
WHERE a. qid='.$this->id.' AND a. userid='.$userid;
$res = get_record_sql($sql);
if ($res->Attempts < 3)
{
return true;
}
else
{
return false;
}
}
else
{
return true;
}
7. Додано метод has_4scrolls для того, щов вияснити, чи є в опитувальнику питання з кривої акцентів:
/**
* Checks if there is a field with 4 scrolls
*
* @author Stepan
* @return bool
*/
function has_4scrolls($section = 0)
{
if (empty($this->questions))
{
return false;
}
else if ($section <= 0)
{
foreach ($this->questions as $question)
{
if ($question->type == '4 Scrolls')
{
return true;
}
}
}
else
{
foreach ($this->questionsbysec[$section] as $question)
{
if ($question->type == '4 Scrolls')
{
return true;
}
}
}
return false;
}
8. Додано метод для в виведення результатів опитування у вигляді картинки. Він викликає функцію, яка зчитує з БД відповіді та обраховує середнє значення для A, B, C, D. Цей метод буд розглянуто далі.
/**
* Display result for the accent curve graph type
*
* @author Stepan
* @param int $rid
*/
function display_accent_curve_results($rid)
{
$data = $this->analyse_responses($rid);
foreach ($data as $key => $arr)
{
foreach ($arr as $sector => $value)
{
$dataStr[] = $key.$sector.'='.$value;
}
}
$dataStr = implode('&', $dataStr);
echo '<img src="graph. php?'.$dataStr.'" />';
}
/**
* Display sumary result for the user
*
* @author Stepan
* @param int $rid
*/
function display_accent_curve_user_desire($rids)
{
$data = $this->analyse_user_responses($rids);
foreach ($data as $key => $arr)
{
foreach ($arr as $sector => $value)
{
$dataStr[] = $key.$sector.'='.$value;
}
}
$dataStr = implode('&', $dataStr);
echo '<img src="user_graph. php?'.$dataStr.'" />';
}
9. В метод print_survey_end додано строки, які всталяють файли, які потрібні для віображення скролів (строки 957-963):
if($this->has_4scrolls())
{
echo '<!-- The slider javascript code -->
<script type="text/javascript" src="js/slider. js" ></script>
<!-- The default slider stylessheet -->
<link href="css/slider. css" rel="stylesheet" type="text/css" />';
}
10. Додано метод, який обраховує дані для A, B, C, D та повертає їх у вигляді масиву, зручного для використання:
/**
* Analyses results of the survey - accent curve type
*
* @param int $rid ID of the response. If empty, average is
* calculated for all responses in survey
* @return array
*/
function analyse_responses($rid)
{
if (empty($rid))
{
$sql = 'SELECT avg(r. ANow) ANow, avg(r. BNow) BNow, avg(r. CNow) CNow, avg(r. DNow) DNow,
avg(r. AFuture) AFuture, avg(r. BFuture) BFuture, avg(r. CFuture) CFuture, avg(r. DFuture) DFuture
FROM mdl_questionnaire_response_scrolls r
INNER JOIN mdl_questionnaire_response resp ON r. response_id=resp. id
WHERE resp. survey_id='.$this->survey->id;
}
else
{
$sql = 'SELECT avg(ANow) ANow, avg(BNow) BNow, avg(CNow) CNow, avg(DNow) DNow,
avg(AFuture) AFuture, avg(BFuture) BFuture, avg(CFuture) CFuture, avg(DFuture) DFuture
FROM mdl_questionnaire_response_scrolls
WHERE response_id='.$rid;
}
$row = get_record_sql($sql);
$result = array(
'Now' => array(
'A' => $row->ANow,
'B' => $row->BNow,
'C' => $row->CNow,
'D' => $row->DNow,
),
'Future' => array(
'A' => $row->AFuture,
'B' => $row->BFuture,
'C' => $row->CFuture,
'D' => $row->DFuture,
),
);
return $result;
}
11. Додано метод, який повертає ідентификатори відповідей за ідентификатором користувача, тобто відповідає напитання – а які відповіді дав даний користувач?
/**
* Returns response ids for the current survey for the specified user
*
* @param int $userid
* @return array
*/
function get_rid_by_uid($userid)
{
if (empty($userid)) return array();
$sql = 'SELECT id
FROM mdl_questionnaire_response
WHERE survey_id='.$this->survey->id.' AND username='.$userid;
$res = get_records_sql($sql);
if (is_array($res))
{
foreach ($res as $rid => $_)
{
$result[] = $rid;
}
}
return $result;
}
12. Додано метод, що повертає розрахунки для 3х ліній – стан «бажано» в перший, другий та третії раз:
/**
* Returns data for 3 lines - desirable now, desirable in the future, desirable in perspective
*
* @param int $uid
*/
function analyse_user_responses($rids)
{
if (sizeof($rids) != 3) return array();
$sql = 'SELECT response_id, avg(AFuture) AFuture, avg(BFuture) BFuture, avg(CFuture) CFuture, avg(DFuture) DFuture
FROM mdl_questionnaire_response_scrolls scrolls
INNER JOIN mdl_questionnaire_response resp ON scrolls. response_id=resp. id
WHERE response_id IN ('.implode(',', $rids).') GROUP BY scrolls. response_id
ORDER BY resp. submitted';
$res = get_records_sql($sql);
$keys = array('Now', 'Future', 'Perspective');
$i = 0;
foreach ($res as $row)
{
$result[$keys[$i]] = array(
'A' => $row->AFuture,
'B' => $row->BFuture,
'C' => $row->CFuture,
'D' => $row->DFuture,
);
$i++;
}
return $result;
}
13. Додано метод, який будує навігацію по користувачам:
function survey_results_navbar_by_user($curr_uid)
{
global $CFG;
$sql = 'SELECT u.*, r. id rid, r. submitted sdate
FROM mdl_user u
INNER JOIN mdl_questionnaire_response r ON u. id=r. username
WHERE r. survey_id = '.$this->survey->id.' AND plete=\'Y\'';
if (!($users = get_records_sql($sql)))
{
return;
}
$total = sizeof($users);
$uids = array();
$uidssub = array();
$username = array();
$i = 0;
$curr_pos = -1;
foreach ($users as $user) {
array_push($uids, $user->id);
array_push($uidssub, $user->sdate);
array_push($username, fullname($user));
if ($user->id == $curr_uid)
{
$curr_pos = $i;
}
$i++;
}
$prev_uid = ($curr_pos > 0) ? $uids[$curr_pos - 1] : null;
$next_uid = ($curr_pos < $total - 1) ? $uids[$curr_pos + 1] : null;
$rows_per_page = 1;
$pages = ceil($total / $rows_per_page);
$url = $CFG->wwwroot.'/mod/questionnaire/report. php? where=results&sid='.$this->survey->id;
$mlink = create_function('$i,$r', 'return "<a href=\"'.$url.'&uid=$r&qact=vuser\">$i</a>";');
$linkarr = array();
$display_pos = 1;
if ($prev_uid!= null)
{
array_push($linkarr, "<a href=\"$url&uid=$prev_uid&qact=vuser\">".get_string('previous').'</a>');
}
$ruser = '';
for ($i = 0; $i < $curr_pos; $i++)
{
$ruser = $username[$i];
$title = userdate($uidssub[$i]).' | ' .$ruser;
array_push($linkarr, '<a href="'.$url.'&uid='.$uids[$i].'&qact=vuser" title="'.$title.'">'.$ruser.'</a>');
// $display_pos++;
}
$cur_user = get_record('user', 'id', $uids[$curr_pos]);
array_push($linkarr, '<b>'.fullname($cur_user).'</b>');
for (++$i; $i < $total; $i++)
{
$ruser = $username[$i];
$title = userdate($uidssub[$i]).' | ' .$ruser;
array_push($linkarr, '<a href="'.$url.'&uid='.$uids[$i].'&qact=vuser" title="'.$title.'">'.$ruser.'</a>');
}
if ($next_uid!= null)
{
array_push($linkarr, "<a href=\"$url&uid=$next_uid&qact=vuser\">".get_string('next').'</a>');
}
echo implode(' | ', $linkarr);
}
14. Внесено зміни в метод survey_results для того, щоб показувати узагальнені результати опптування для всях студентів (строки ):
/**
* Added by Stepan
*/
if ($this->has_4scrolls())
{
$data = $this->analyse_responses($_);
foreach ($data as $key => $arr)
{
foreach ($arr as $sector => $value)
{
$dataStr[] = $key.$sector.'='.$value;
}
}
$dataStr = implode('&', $dataStr);
echo '<center><strong>Узагальнені результати</strong><br /><br />
<img src="graph. php?'.$dataStr.'" /></center>';
return;
}
//EOF - Added by Stepan
В файлі, який описує типи питань внесено такі зміни:
1. Додано константу для нового типу питань (строка 29):
define('QUES4SCROLLS', 11);
2. Додано елемент в масив для нового типу питань (строка 43):
QUES4SCROLLS => 'four_scrolls',
3. Додано властивість, в якій зберігається номер поточного питання
/**
* Number of the question. Needed for the 4scrolls type of question
* @var integer $qnum
*/
var $qnum;
4. Додано метод для збереження даних для питань кривої акцентів:
function insert_response_scrolls($rid, $formdata)
{
$data = $formdata->{'q'.$this->id};
$record = new Object();
$record->response_id = $rid;
$record->question_id = $this->id;
$record->ANow = $data['Now']['A'];
$record->BNow = $data['Now']['B'];
$record->CNow = $data['Now']['C'];
$record->DNow = $data['Now']['D'];
$record->AFuture = $data['Future']['A'];
$record->BFuture = $data['Future']['B'];
$record->CFuture = $data['Future']['C'];
$record->DFuture = $data['Future']['D'];
return insert_record('questionnaire_'.$this->response_table, $record);
}
5. Додано метод для відображення питаня кривої акцентів
/**
* Forms output for the 4 scrolls input field, for the accent curve.
*
* @param mixed $data
*/
function four_scrolls_survey_display($data)
{
if (stristr($this->content, '<ul>'))
{
preg_match_all('!<li>(.*?)</li>!is', $this->content, $matches);
$qParts = clear_array($matches[1]);
array_walk($qParts, 'strip_tags');
}
elseif (stristr($this->content, '<br />'))
{
$qParts = clear_array(explode('<br />', $this->content));
}
elseif (stristr($this->content, '<br>'))
{
$qParts = clear_array(explode('<br>', $this->content));
}
elseif (stristr($this->content, "\n"))
{
$qParts = clear_array(explode("\n", $this->content));
}
$i = 0;
if (!empty($data->rid))
{
$sql = "SELECT *
FROM mdl_questionnaire_response_scrolls
WHERE response_id=".$data->rid." AND question_id=".$this->id;
$res = get_record_sql($sql);
}
foreach ($this->choices as $chID => $chVal)
{
switch ($i)
{
case 0:
{
$qVariants[0]['A']['ID'] = $chID;
$qVariants[0]['A']['Text'] = $chVal->content;
$qVariants[0]['A']['Val'] = empty($res) ? array(50,50) : array($res->ANow, $res->AFuture);
break;
}
case 1:
{
$qVariants[0]['C']['ID'] = $chID;
$qVariants[0]['C']['Text'] = $chVal->content;
$qVariants[0]['C']['Val'] = empty($res) ? array(50,50) : array($res->CNow, $res->CFuture);
break;
}
case 2:
{
$qVariants[1]['B']['ID'] = $chID;
$qVariants[1]['B']['Text'] = $chVal->content;
$qVariants[1]['B']['Val'] = empty($res) ? array(50,50) : array($res->BNow, $res->BFuture);
break;
}
case 3:
{
$qVariants[1]['D']['ID'] = $chID;
$qVariants[1]['D']['Text'] = $chVal->content;
$qVariants[1]['D']['Val'] = empty($res) ? array(50,50) : array($res->DNow, $res->DFuture);
break;
}
}
$i++;
}
$output = '<table id="q'.$this->qnum.'" width="100%" border="1" bgcolor="#FFFFFF" bordercolor="#E0E0E0" cellspacing="0" cellpadding="3" align="center">';
foreach ($qParts as $k => $txt)
{
$output .= '<tr bgcolor="#EFEFEF">
<td align="center" width="25">'.$this->qnum.'.'.($k+1).'</td>
<td id="q'.$this->id.'"><strong>'.$txt.'</strong></td>
<td align="center">Зараз</td>
<td align="center">Бажано</td>
</tr>';
foreach ($qVariants[$k] as $sect => $data)
{
$output .= '
<tr>
<td align="center"><strong>'.$sect.'</strong></td>
<td>'.$data['Text'].'</td>'."\n";
if ($sect == 'A' || $sect == 'B')
{
$output.= '<td align="right" rowspan="2" width="70">
<div class="vslider_track"><div class="slider_slit"> </div>
<div id="q'.$this->qnum.'_'.$k.'z'.$this->qnum.'" class="slider" orientation="vertical" distance="50"
display="q'.$this->qnum.'_'.$k.'z'.$this->qnum.'" style="top: '.(50-$data['Val'][0]/2).'px;"> </div>
</div>
<input id="up_q'.$this->qnum.'_'.$k.'z'.$this->qnum.'" name="q'.$this->id.'[Now]['.$sect.']" value="'.$data['Val'][0].'" class="slider_display" type="text" from="0" to="100" valuecount="200" value="50" typelock="on" style="margin-top:7px;" />
<input id="dn_q'.$this->qnum.'_'.$k.'z'.$this->qnum.'" name="q'.$this->id.'[Now]['.($sect == 'A' ? 'C' : 'D').']" value="'.(100-$data['Val'][0]).'" class="slider_display" type="text" from="0" to="100" valuecount="200" value="50" typelock="on" />
</td>
<td align="right" rowspan="2" width="70">
<div class="vslider_track"><div class="slider_slit"> </div>
<div id="q'.$this->qnum.'_'.$k.'b'.$this->qnum.'" class="slider" orientation="vertical" distance="50"
display="q'.$this->qnum.'_'.$k.'b'.$this->qnum.'" style="top: '.(50-$data['Val'][1]/2).'px;"> </div>
</div>
<input id="up_q'.$this->qnum.'_'.$k.'b'.$this->qnum.'" name="q'.$this->id.'[Future]['.$sect.']" value="'.$data['Val'][1].'" class="slider_display" type="text" from="0" to="100" valuecount="200" value="50" typelock="on" style="margin-top:7px;" />
<input id="dn_q'.$this->qnum.'_'.$k.'b'.$this->qnum.'" name="q'.$this->id.'[Future]['.($sect == 'A' ? 'C' : 'D').']" value="'.(100-$data['Val'][1]).'" class="slider_display" type="text" from="0" to="100" valuecount="200" value="50" typelock="on" />
</td>
</tr>
';
}
}
}
$output .= "\n</table>";
echo $output;
}
6. Змінено метод questionstart_survey_display щоб не виводився стандартний початок питання (строкт 849-854):
if ($this->type_id == QUESSECTIONTEXT ||
$this->type_id == QUES4SCROLLS)
{
$this->qnum = $qnum;
return;
}
Крім цих двох файлів, було створен два файли, які малюють графіки засобами PHP, що дає можливість користувачу зберегти графік:
graph.php
<?php
$im = imagecreatefromjpeg('images/graph. jpg');
$red = imagecolorallocate($im, 0xFF, 0x00, 0x00);
$yellow = imagecolorallocate($im, 0xFF, 0xFF, 0x00);
extract($_GET);
//echo "<pre>";
//print_r($data);
//echo "</pre>";
$xAxis = 225;
$yAxis = 225;
$scale = 2.65;
$Now['A']['X'] = round(-$NowA*$scale/1.41+$xAxis);
$Now['A']['Y'] = round(-$NowA*$scale/1.41+$yAxis);
$Now['B']['X'] = round($NowB*$scale/1.41+$xAxis);
$Now['B']['Y'] = round(-$NowB*$scale/1.41+$yAxis);
$Now['C']['X'] = round($NowC*$scale/1.41+$xAxis);
$Now['C']['Y'] = round($NowC*$scale/1.41+$yAxis);
$Now['D']['X'] = round(-$NowD*$scale/1.41+$xAxis);
$Now['D']['Y'] = round($NowD*$scale/1.41+$yAxis);
$Future['A']['X'] = round(-$FutureA*$scale/1.41+$xAxis);
$Future['A']['Y'] = round(-$FutureA*$scale/1.41+$xAxis);
$Future['B']['X'] = round($FutureB*$scale/1.41+$xAxis);
$Future['B']['Y'] = round(-$FutureB*$scale/1.41+$xAxis);
$Future['C']['X'] = round($FutureC*$scale/1.41+$xAxis);
$Future['C']['Y'] = round($FutureC*$scale/1.41+$xAxis);
$Future['D']['X'] = round(-$FutureD*$scale/1.41+$xAxis);
$Future['D']['Y'] = round($FutureD*$scale/1.41+$xAxis);
//output current state
imagefilledrectangle($im, $Now['A']['X']-2, $Now['A']['Y']-2,$Now['A']['X']+2, $Now['A']['Y']+2, $red);
imagefilledrectangle($im, $Now['B']['X']-2, $Now['B']['Y']-2,$Now['B']['X']+2, $Now['B']['Y']+2, $red);
imagefilledrectangle($im, $Now['C']['X']-2, $Now['C']['Y']-2,$Now['C']['X']+2, $Now['C']['Y']+2, $red);
imagefilledrectangle($im, $Now['D']['X']-2, $Now['D']['Y']-2,$Now['D']['X']+2, $Now['D']['Y']+2, $red);
imageline($im, $Now['A']['X'],
$Now['A']['Y'],
$Now['B']['X'],
$Now['B']['Y'],
$red);
imageline($im, $Now['B']['X'],
$Now['B']['Y'],
$Now['C']['X'],
$Now['C']['Y'],
$red);
imageline($im, $Now['C']['X'],
$Now['C']['Y'],
$Now['D']['X'],
$Now['D']['Y'],
$red);
imageline($im, $Now['D']['X'],
$Now['D']['Y'],
$Now['A']['X'],
$Now['A']['Y'],
$red);
//output desirable state
imagefilledrectangle($im, $Future['A']['X']-2, $Future['A']['Y']-2,$Future['A']['X']+2, $Future['A']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['B']['X']-2, $Future['B']['Y']-2,$Future['B']['X']+2, $Future['B']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['C']['X']-2, $Future['C']['Y']-2,$Future['C']['X']+2, $Future['C']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['D']['X']-2, $Future['D']['Y']-2,$Future['D']['X']+2, $Future['D']['Y']+2, $yellow);
imageline($im, $Future['A']['X'],
$Future['A']['Y'],
$Future['B']['X'],
$Future['B']['Y'],
$yellow);
imageline($im, $Future['B']['X'],
$Future['B']['Y'],
$Future['C']['X'],
$Future['C']['Y'],
$yellow);
imageline($im, $Future['C']['X'],
$Future['C']['Y'],
$Future['D']['X'],
$Future['D']['Y'],
$yellow);
imageline($im, $Future['D']['X'],
$Future['D']['Y'],
$Future['A']['X'],
$Future['A']['Y'],
$yellow);
imagepng($im);
?>
user_graph.php
<?php
$im = imagecreatefromjpeg('images/graph2.jpg');
$red = imagecolorallocate($im, 0xFF, 0x00, 0x00);
$yellow = imagecolorallocate($im, 0xFF, 0xFF, 0x00);
$green = imagecolorallocate($im, 0x00, 0xFF, 0x00);
extract($_GET);
//echo "<pre>";
//print_r($data);
//echo "</pre>";
$xAxis = 225;
$yAxis = 225;
$scale = 2.65;
$Now['A']['X'] = round(-$NowA*$scale/1.41+$xAxis);
$Now['A']['Y'] = round(-$NowA*$scale/1.41+$yAxis);
$Now['B']['X'] = round($NowB*$scale/1.41+$xAxis);
$Now['B']['Y'] = round(-$NowB*$scale/1.41+$yAxis);
$Now['C']['X'] = round($NowC*$scale/1.41+$xAxis);
$Now['C']['Y'] = round($NowC*$scale/1.41+$yAxis);
$Now['D']['X'] = round(-$NowD*$scale/1.41+$xAxis);
$Now['D']['Y'] = round($NowD*$scale/1.41+$yAxis);
$Future['A']['X'] = round(-$FutureA*$scale/1.41+$xAxis);
$Future['A']['Y'] = round(-$FutureA*$scale/1.41+$xAxis);
$Future['B']['X'] = round($FutureB*$scale/1.41+$xAxis);
$Future['B']['Y'] = round(-$FutureB*$scale/1.41+$xAxis);
$Future['C']['X'] = round($FutureC*$scale/1.41+$xAxis);
$Future['C']['Y'] = round($FutureC*$scale/1.41+$xAxis);
$Future['D']['X'] = round(-$FutureD*$scale/1.41+$xAxis);
$Future['D']['Y'] = round($FutureD*$scale/1.41+$xAxis);
$Perspective['A']['X'] = round(-$PerspectiveA*$scale/1.41+$xAxis);
$Perspective['A']['Y'] = round(-$PerspectiveA*$scale/1.41+$xAxis);
$Perspective['B']['X'] = round($PerspectiveB*$scale/1.41+$xAxis);
$Perspective['B']['Y'] = round(-$PerspectiveB*$scale/1.41+$xAxis);
$Perspective['C']['X'] = round($PerspectiveC*$scale/1.41+$xAxis);
$Perspective['C']['Y'] = round($PerspectiveC*$scale/1.41+$xAxis);
$Perspective['D']['X'] = round(-$PerspectiveD*$scale/1.41+$xAxis);
$Perspective['D']['Y'] = round($PerspectiveD*$scale/1.41+$xAxis);
//output current state
imagefilledrectangle($im, $Now['A']['X']-2, $Now['A']['Y']-2,$Now['A']['X']+2, $Now['A']['Y']+2, $red);
imagefilledrectangle($im, $Now['B']['X']-2, $Now['B']['Y']-2,$Now['B']['X']+2, $Now['B']['Y']+2, $red);
imagefilledrectangle($im, $Now['C']['X']-2, $Now['C']['Y']-2,$Now['C']['X']+2, $Now['C']['Y']+2, $red);
imagefilledrectangle($im, $Now['D']['X']-2, $Now['D']['Y']-2,$Now['D']['X']+2, $Now['D']['Y']+2, $red);
imageline($im, $Now['A']['X'],
$Now['A']['Y'],
$Now['B']['X'],
$Now['B']['Y'],
$red);
imageline($im, $Now['B']['X'],
$Now['B']['Y'],
$Now['C']['X'],
$Now['C']['Y'],
$red);
imageline($im, $Now['C']['X'],
$Now['C']['Y'],
$Now['D']['X'],
$Now['D']['Y'],
$red);
imageline($im, $Now['D']['X'],
$Now['D']['Y'],
$Now['A']['X'],
$Now['A']['Y'],
$red);
//output desirable state
imagefilledrectangle($im, $Future['A']['X']-2, $Future['A']['Y']-2,$Future['A']['X']+2, $Future['A']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['B']['X']-2, $Future['B']['Y']-2,$Future['B']['X']+2, $Future['B']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['C']['X']-2, $Future['C']['Y']-2,$Future['C']['X']+2, $Future['C']['Y']+2, $yellow);
imagefilledrectangle($im, $Future['D']['X']-2, $Future['D']['Y']-2,$Future['D']['X']+2, $Future['D']['Y']+2, $yellow);
imageline($im, $Future['A']['X'],
$Future['A']['Y'],
$Future['B']['X'],
$Future['B']['Y'],
$yellow);
imageline($im, $Future['B']['X'],
$Future['B']['Y'],
$Future['C']['X'],
$Future['C']['Y'],
$yellow);
imageline($im, $Future['C']['X'],
$Future['C']['Y'],
$Future['D']['X'],
$Future['D']['Y'],
$yellow);
imageline($im, $Future['D']['X'],
$Future['D']['Y'],
$Future['A']['X'],
$Future['A']['Y'],
$yellow);
//output perspective state
imagefilledrectangle($im, $Perspective['A']['X']-2, $Perspective['A']['Y']-2,$Perspective['A']['X']+2, $Perspective['A']['Y']+2, $green);
imagefilledrectangle($im, $Perspective['B']['X']-2, $Perspective['B']['Y']-2,$Perspective['B']['X']+2, $Perspective['B']['Y']+2, $green);
imagefilledrectangle($im, $Perspective['C']['X']-2, $Perspective['C']['Y']-2,$Perspective['C']['X']+2, $Perspective['C']['Y']+2, $green);
imagefilledrectangle($im, $Perspective['D']['X']-2, $Perspective['D']['Y']-2,$Perspective['D']['X']+2, $Perspective['D']['Y']+2, $green);
imageline($im, $Perspective['A']['X'],
$Perspective['A']['Y'],
$Perspective['B']['X'],
$Perspective['B']['Y'],
$green);
imageline($im, $Perspective['B']['X'],
$Perspective['B']['Y'],
$Perspective['C']['X'],
$Perspective['C']['Y'],
$green);
imageline($im, $Perspective['C']['X'],
$Perspective['C']['Y'],
$Perspective['D']['X'],
$Perspective['D']['Y'],
$green);
imageline($im, $Perspective['D']['X'],
$Perspective['D']['Y'],
$Perspective['A']['X'],
$Perspective['A']['Y'],
$green);
imagepng($im);
?>
Крім цього, змінено такі файли:
1. В файлі results.inc, строки 37-50:
elseif (!empty($uid))
{
echo '<div align="center">';
$questionnaire->survey_results_navbar_by_user($uid);
echo '</div>';
echo'<table class = "active"><tr><td>';
$select = 'survey_id = '.$sid.' AND username = '.$uid.' AND complete=\'Y\'';
$resps = get_records_select('questionnaire_response', $select, ‘submitted asc’);
$ret = $questionnaire->view_all_responses($resps);
echo '</td></tr></table>';
echo '<div align="center"><br />';
$questionnaire->survey_results_navbar_by_user($uid);
echo '</div>';
}
генерують сторінку коли обрана навігаця по користувачам.
2. Файл report. php
1. Строка 12. Додано необов'язковий параметр $uid:
$uid = optional_param('uid', false, PARAM_INT);
2. Строка 51. Отримання строки для конкретної мови:
$strviewbyuser = get_string('viewbyuser', 'questionnaire');
3. Строка 81-86. Обробка запиту на виведення відповідей на анаету за користувачами:
case 'viewbyuser':
$qact = 'vuser';
$byuser = true;
$byresponse = false;
$uid = false;
break;
4. Строка 280. Додана обробка запиту на виведення відповідей на анкету за користувачами
case 'vuser':
5. Строки 308-333. Отримання поточного ідентифікатора користувача та його повного імені. Якщо нічого не було передано, то беремо першого:
elseif ($byuser || $uid)
{
if ($uid === false)
{
$users = get_records_sql('SELECT DISTINCT username UID FROM mdl_questionnaire_response ORDER BY submitted');//('questionnaire_response', 'survey_id', $sid, 'id', '*', 0, 1);
$user = current($users);
$uid = $user->UID;
}
/*else
{
$resp = get_record('questionnaire_response', 'id', $rid);
}*/
if (is_numeric($uid)) {
if ($user = get_record('user', 'id', $uid)) {
$ruser = fullname($user);
}
else
{
$ruser = '- '.get_string('unknown', 'questionnaire').' -';
}
}
else
{
$ruser = $uid;
}
}
6. Строки 373-376. Виведення кнопки, яка дає можливість просмотри відповідей за користувачами, якщо це крива акцентів:
if ($questionnaire->has_4scrolls())
echo '<input type="submit" name="viewbyuser" value="'.$strviewbyuser.'" />';
else
echo '<input type="submit" name="viewbyresponse" value="'.$strviewbyresponse.'" />';
3. Файл myreport.php. Строка 103. При виведенні результатів сортуємо їх за датою проходження.
$resps = get_records_select('questionnaire_response', $select, 'submitted asc');
Загальне уявлення про роботу модуля.
I. Виведення опитування.
1. Визначається, чи проходив цей користувач опитування.
i) Якщо так, то скільки разів.
(1) Якщо пройшов 3 рази, то виводимо 3 графіки для кожного разу та еволюцію поглядів.
(2) Якщо менше 3х, то отримуємо всі питання і виводимо їх по черзі. Кожне питання виводиться за домогою класу questionnaire_question. Для кожного типу питання працюють свої методи
ii) Якщо ні, то також виводимо всі питання


