diff options
Diffstat (limited to 'lib/classes/InstituteCalendarHelper.php')
| -rw-r--r-- | lib/classes/InstituteCalendarHelper.php | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/lib/classes/InstituteCalendarHelper.php b/lib/classes/InstituteCalendarHelper.php new file mode 100644 index 0000000..6c934b4 --- /dev/null +++ b/lib/classes/InstituteCalendarHelper.php @@ -0,0 +1,810 @@ +<?php + +/** + * InstituteCalendarHelper.php - class for institute calendar convenience functions + * + * @author Timo Hartge <hartge@data-quest> + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * + */ + +class InstituteCalendarHelper +{ + const COLUMN_DATAFIELD_ID = '69f6485f3c937766866a03d9d642ecbb'; + const COLOR_DATAFIELD_ID = '41cda2be71fe9efd6e28b853fc0681f3'; + const INST_DEFAULT_COLOR_DATAFIELD_ID = '0c63321a8e93b3ccc927611709248e07'; + const DEFAULT_EVENT_COLOR = '#899ab9'; + + /** + * Returns the default calendar columns. + * + * @return array default column names + */ + private static function getDefaultColumns() + { + return [ + 1 => ['Spalte 1', 1], + 2 => ['Spalte 2', 1], + 3 => ['Spalte 3', 1], + 4 => ['Spalte 4', 1], + 5 => ['Spalte 5', 1], + 6 => ['Spalte 6', 1] + ]; + } + + /** + * Fetches the stores columns merged with defaults. + * + * @param string $institut_id + * @param boolean $only_visible only return visible columns + * + * @return array column array in a fullcalender expected format + */ + public static function getResourceColumns($institut_id, $only_visible = false) + { + $columns = []; + $inst_columns = [ + 0 => ['Sammelspalte', 1] + ]; + + $db_inst_columns = InstitutePlanColumn::findByInstitute($institut_id); + + if ($db_inst_columns) { + foreach ($db_inst_columns as $col_info) { + $inst_columns[$col_info['column']] = [$col_info['name'], $col_info['visible']]; + } + } else { + $inst_columns = array_merge($inst_columns, self::getDefaultColumns()); + } + foreach ($inst_columns as $id => $info) { + if ($only_visible && !$info[1]) continue; + $columns[] = ['id' => $id, 'title' => $info[0], 'visible' => $info[1]]; + } + return $columns; + } + + /** + * Adds the default resource columns + * + * @param string $institut_id + * + * @return int last resource column number + */ + public static function addDefaultResourceColumns($institut_id) + { + $max_col = 0; + foreach (self::getDefaultColumns() as $col_id => $col_info) { + $new_col = new InstitutePlanColumn([$institut_id, $col_id]); + $new_col->name = $col_info[0]; + $new_col->visible = $col_info[1]; + if ($new_col->store()) { + $max_col = $col_id; + } + } + return $max_col; + } + + /** + * Adds a resource column + * + * @param string $institut_id + * @param string $name + * @param int $specific_column_number + * + * @return int number of affected rows + */ + public static function addResourceColumn($institut_id, $name, $specific_column_number = 0) + { + $last_col = InstitutePlanColumn::getLastColumnOfInstitute($institut_id); + if ($last_col !== null) { + $max_col = $last_col->column; + } else { + $max_col = self::addDefaultResourceColumns($institut_id); + } + $column_number = $specific_column_number>0?$specific_column_number:intval($max_col)+1; + $new_col = new InstitutePlanColumn([$institut_id, $column_number]); + $new_col->name = $name; + $new_col->visible = 1; + return $new_col->store(); + } + + /** + * Looks up column id for course events + * + * @param Course $course + * + * @return array course events with column id + */ + public static function getCourseEventcolumns(Course $course) + { + $df = DatafieldEntryModel::findByModel($course, self::COLUMN_DATAFIELD_ID); + if ($df[0] && $df[0]->content) { + $event_columns = unserialize($df[0]->content); + } else { + $event_columns = []; + } + return $event_columns; + } + + /** + * Sets the column id for course events + * + * @param Course $course + * @param string $event_id SeminarCycleDate id + * @param string $institut_id + * @param string $column number of the column + * + * @return bool stored + */ + public static function setCourseEventcolumn($course, $event_id, $institut_id, $column) + { + $df = DatafieldEntryModel::findByModel($course, self::COLUMN_DATAFIELD_ID); + if ($df[0]) { + $event_columns = self::getCourseEventcolumns($course); + if (!is_array($event_columns[$event_id])) { + unset($event_columns[$event_id]); + } + $event_columns[$event_id][$institut_id] = $column; + $df[0]->content = serialize($event_columns); + return $df[0]->store(); + } + return false; + } + + /** + * Looks up color value for course events + * + * @param Course $course + * + * @return array course events with color value + */ + public static function getCourseEventcolors($course) + { + $df = DatafieldEntryModel::findByModel($course, self::COLOR_DATAFIELD_ID); + if ($df[0] && $df[0]->content) { + $event_colors = unserialize($df[0]->content); + } else { + $event_colors = []; + } + return $event_colors; + } + + /** + * Sets color value for course events + * + * @param Course $course + * @param string $event_id SeminarCycleDate id + * @param string $institut_id + * @param string $color colorcode + * + * @return bool stored + */ + public static function setCourseEventcolor($course, $event_id, $institut_id, $color) + { + $df = DatafieldEntryModel::findByModel($course, self::COLOR_DATAFIELD_ID); + if ($df[0]) { + $event_colors = self::getCourseEventcolors($course); + if (!is_array($event_colors[$event_id])) { + unset($event_colors[$event_id]); + } + $event_colors[$event_id][$institut_id] = $color; + $df[0]->content = serialize($event_colors); + return $df[0]->store(); + } + return false; + } + + /** + * Looks up default color value for institute course events + * + * @param SimpleORMap $context + * + * @return array course events with color value + */ + public static function getInstituteDefaultEventcolors($context) + { + $df = DatafieldEntryModel::findByModel($context, self::INST_DEFAULT_COLOR_DATAFIELD_ID); + if ($df && $df[0]->content) { + $event_colors = unserialize($df[0]->content); + } else { + $event_colors = []; + } + return $event_colors; + } + + /** + * Sets default institute course events color value for semtypes + * + * @param SimpleORMap $context + * @param string $semtype + * @param string $color colorcode + * + * @return bool stored + */ + public static function setInstituteDefaultEventcolor($context, $semtype, $color) + { + $df = DatafieldEntryModel::findByModel($context, self::INST_DEFAULT_COLOR_DATAFIELD_ID); + if ($df[0]) { + $event_colors = self::getInstituteDefaultEventcolors($context); + $event_colors[$semtype['name']] = $color; + $df[0]->content = serialize($event_colors); + return $df[0]->store(); + } + return false; + } + + /** + * Sets color value for every course events of given courses semtype + * + * @param Course $course + * @param string $institut_id + * @param string $color colorcode + * + * @return bool stored + */ + public static function setSemtypeEventcolor($course, $institut_id, $color) + { + $semtype = $course->getSemType(); + $institut = Institute::find($institut_id); + if ($institut) { + self::setInstituteDefaultEventcolor($institut, $semtype, $color); + } + $courses = Course::findBySQL('status =? AND Institut_id=?', [$semtype['id'], $course->institut_id]); + if ($courses) { + foreach ($courses as $semtype_course) { + foreach (SeminarCycleDate::findBySeminar($semtype_course->seminar_id) as $cycle_date) { + self::setCourseEventcolor($semtype_course, $cycle_date->id, $institut_id, $color); + } + } + return true; + } + return false; + } + + /** + * Prepares an array of course id and names for creation of dropable calendar events + * + * @param array $courses Array of courses + * @param array $semester Semester + * + * @return array prepared array + */ + public static function getEventlessCourses($courses, $semester = null) + { + $eventless = []; + foreach (array_keys($courses) as $cid) { + $course = Course::find($cid); + $cycle_dates = SeminarCycleDate::findBySeminar($course->seminar_id); + if (count($cycle_dates) < 1) { + $eventless[$cid] = $course->getFullName('number-name'); + } elseif ($semester) { + $has_date_in_semester = false; + foreach ($cycle_dates as $cycle_date) { + foreach ($cycle_date->getAllDates() as $course_date) { + if ($course_date->date >= $semester->beginn && $course_date->date <= $semester->ende) { + $has_date_in_semester = true; + break; + } + } + if ($has_date_in_semester) break; + } + if (!$has_date_in_semester) { + $eventless[$cid] = $course->getFullName('number-name'); + } + } + } + return $eventless; + } + + /** + * Creates FullCalendar event date of course events + * + * @param array $courses Array of courses + * @param string $institut_id + * @param array $semester Semester + * @param array $specific_weekday fetch only events for specific weekday + * + * @return array fullcalendar events + */ + public static function getEvents($courses, $institut_id, $semester = null, $specific_weekday = null) + { + $today = date('w'); + + $user_insts = array_map(function ($arr) { + return $arr['Institut_id']; + }, Institute::getMyInstitutes($GLOBALS['user']->id)); + + $min_time = explode(':', Config::get()->INSTITUTE_COURSE_PLAN_START_HOUR); + $minbigtime = (int) $min_time[0]; + $max_time = explode(':', Config::get()->INSTITUTE_COURSE_PLAN_END_HOUR); + $maxbigtime = (int) $max_time[0]; + + $institut = Institute::find($institut_id); + + if (!$institut) { + return []; + } + + $inst_default_colors = self::getInstituteDefaultEventcolors($institut); + + $events = []; + Course::findEachMany(function ($course) use ( + $courses, + &$events, + $today, + $minbigtime, + $maxbigtime, + $user_insts, + $institut_id, + $inst_default_colors, + $semester, + $specific_weekday + ) { + $semtype = $course->getSemType(); + + $event_columns = self::getCourseEventcolumns($course) ?: []; + $event_colors = self::getCourseEventcolors($course) ?: []; + + if (in_array($course->institut_id, $user_insts)) { + $is_editable = true; + $is_start_editable = !LockRules::Check($course->id, 'room_time'); + $is_duration_editable = false; + } else { + $is_editable = false; + $is_start_editable = false; + $is_duration_editable = false; + } + + foreach (SeminarCycleDate::findBySeminar($course->seminar_id) as $cycle_date) { + if ($semester) { + $has_date_in_semester = false; + foreach ($cycle_date->getAllDates() as $course_date) { + if ($course_date->date >= $semester->beginn && $course_date->date <= $semester->ende) { + $has_date_in_semester = true; + break; + } + } + if (!$has_date_in_semester) { + continue; + } + } + + if (is_numeric($specific_weekday) && $specific_weekday != $cycle_date['weekday']) { + continue; + } + + $conform = true; + + if ($cycle_date['weekday'] == 0) { + $day_offset = 7 - $today; + } else { + $day_offset = $cycle_date['weekday'] - $today; + } + + $start_time = explode(':', $cycle_date['start_time']); + $bigtime = (int) $start_time[0]; + if ($bigtime > $maxbigtime || $bigtime < $minbigtime) { + $conform = false; + } elseif ($bigtime % 2) { + $bigtime--; + } + $start_time = $bigtime . ':00:00'; + + $end_time = explode(':', $start_time); + $end_time[0] += 2; + $end_time = implode(':', $end_time); + + $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event'); + $name = $course->getFullName('number-name'); + + if ($start_time != $cycle_date['start_time'] && $end_time != $cycle_date['end_time']) { + $start = self::iso8601date(strtotime($day_offset . ' days'), $cycle_date['start_time']); + $end = self::iso8601date(strtotime($day_offset . ' days'), $cycle_date['end_time']); + $backgroundcolor = '#6c737a'; + $textcolor = '#ffffff'; + } else { + $start = self::iso8601date(strtotime($day_offset . ' days'), $start_time); + $end = self::iso8601date(strtotime($day_offset . ' days'), $end_time); + + $backgroundcolor = null; + if (array_key_exists($cycle_date->id, $event_colors)) { + if (is_array($event_colors[$cycle_date->id]) && array_key_exists($institut_id, $event_colors[$cycle_date->id])) { + $backgroundcolor = $event_colors[$cycle_date->id][$institut_id]; + } + } + if (!$backgroundcolor) { + $backgroundcolor = array_key_exists($semtype['name'], $inst_default_colors) + ? $inst_default_colors[$semtype['name']] + : self::DEFAULT_EVENT_COLOR; + } + + $textcolor = '#ffffff'; + if (self::calculateLuminosityRatio($backgroundcolor, $textcolor) < 3) { + $textcolor = '#000000'; + } + } + if (!$is_editable) { + $backgroundcolor = '#c4c7c9'; + $textcolor = '#000000'; + } + + $resource_column = '0'; + if (array_key_exists($cycle_date->id, $event_columns)) { + if (is_array($event_columns[$cycle_date->id]) && array_key_exists($institut_id, $event_columns[$cycle_date->id])) { + $resource_column = $event_columns[$cycle_date->id][$institut_id]; + } + } + + $events[] = [ + 'resourceId' => $resource_column, + 'id' => $cycle_date->id, + 'title' => $name, + 'start' => $start, + 'end' => $end, + 'textColor' => $textcolor, + 'backgroundColor' => $backgroundcolor, + 'borderColor' => '#000', + 'editable' => $is_editable, + 'startEditable' => $is_start_editable, + 'durationEditable' => $is_duration_editable, + 'resourceEditable' => true, + 'studip_api_urls' => ['move' => $move_url], + 'studip_view_urls' => ['edit' => URLHelper::getURL('dispatch.php/course/details/index/' . $cycle_date->seminar_id)], + 'metadate_id' => $cycle_date->metadate_id, + 'course_id' => $cycle_date->seminar_id, + 'tooltip' => self::getCycleInfos($course, $cycle_date), + 'icon' => $is_start_editable ? '' : 'lock-locked', + 'conform' => $conform, + ]; + } + }, array_keys($courses)); + + return $events; + } + + /** + * Creates a fullcalendar event of given SeminarCycleDate + * + * @param SeminarCycleDate $cycle_date + * @param string $institut_id + * + * @return array enriched course info string for tooltip + */ + public static function getCycleEvent($cycle_date, $institut_id) + { + $course = Course::find($cycle_date->seminar_id); + $semtype = $course->getSemType(); + $institut = Institute::find($institut_id); + $inst_default_colors = self::getInstituteDefaultEventcolors($institut); + + $today = date('w'); + $user_insts = array_map(function ($arr) { + return $arr['Institut_id']; + }, Institute::getMyInstitutes($GLOBALS['user']->id)); + + $min_time = explode(':', Config::get()->INSTITUTE_COURSE_PLAN_START_HOUR); + $minbigtime = (int) $min_time[0]; + $max_time = explode(':', Config::get()->INSTITUTE_COURSE_PLAN_END_HOUR); + $maxbigtime = (int) $max_time[0]; + + $start_time = explode(':', $cycle_date['start_time']); + $bigtime = (int) $start_time[0]; + + if ($bigtime > $maxbigtime || $bigtime < $minbigtime) { + return null; + } elseif ($bigtime % 2) { + $bigtime--; + } + $start_time = $bigtime . ':00:00'; + + $end_time = explode(':', $start_time); + $end_time[0] += 2; + $end_time = implode(':', $end_time); + + if (in_array($course->institut_id, $user_insts)) { + $is_editable = true; + $is_start_editable = !LockRules::Check($cycle_date->seminar_id, 'room_time'); + $is_duration_editable = false; + } else { + $is_editable = false; + $is_start_editable = false; + $is_duration_editable = false; + } + + if ($cycle_date['weekday'] == 0) { + $day_offset = (7 - $today); + } else { + $day_offset = ($cycle_date['weekday'] - $today); + } + + $event_columns = self::getCourseEventcolumns($course); + $event_colors = self::getCourseEventcolors($course); + + $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event'); + $name = $course->getFullName('number-name'); + + if ($start_time != $cycle_date['start_time'] && $end_time != $cycle_date['end_time']) { + $start = self::iso8601date(strtotime($day_offset . ' days'), $cycle_date['start_time']); + $end = self::iso8601date(strtotime($day_offset . ' days'), $cycle_date['end_time']); + $backgroundcolor = '#6c737a'; + $textcolor = '#ffffff'; + } else { + $start = self::iso8601date(strtotime($day_offset . ' days'), $start_time); + $end = self::iso8601date(strtotime($day_offset . ' days'), $end_time); + + $backgroundcolor = null; + if (array_key_exists($cycle_date->id, $event_colors)) { + if (is_array($event_colors[$cycle_date->id]) && array_key_exists($institut_id, $event_colors[$cycle_date->id])) { + $backgroundcolor = $event_colors[$cycle_date->id][$institut_id]; + } + } + if (!$backgroundcolor) { + $backgroundcolor = array_key_exists($semtype['name'], $inst_default_colors)?$inst_default_colors[$semtype['name']]:self::DEFAULT_EVENT_COLOR; + } + + $textcolor = '#ffffff'; + if (self::calculateLuminosityRatio($backgroundcolor, $textcolor) < 3) { + $textcolor = '#000000'; + } + } + if (!$is_editable) { + $backgroundcolor = '#c4c7c9'; + $textcolor = '#000000'; + } + + $resource_column = '0'; + if (array_key_exists($cycle_date->id, $event_columns)) { + if (is_array($event_columns[$cycle_date->id]) && array_key_exists($institut_id, $event_columns[$cycle_date->id])) { + $resource_column = $event_columns[$cycle_date->id][$institut_id]; + } + } + + return [ + 'resourceId' => $resource_column, + 'id' => $cycle_date->id, + 'title' => $name, + 'start' => $start, + 'end' => $end, + 'textColor' => $textcolor, + 'backgroundColor' => $backgroundcolor, + 'borderColor' => '#000', + 'editable' => $is_editable, + 'startEditable' => $is_start_editable, + 'durationEditable' => $is_duration_editable, + 'resourceEditable' => true, + 'studip_api_urls' => ['move' => $move_url], + 'studip_view_urls' => ['edit' => URLHelper::getURL('dispatch.php/course/details/index/' . $cycle_date->seminar_id)], + 'metadate_id' => $cycle_date->metadate_id, + 'course_id' => $cycle_date->seminar_id, + 'tooltip' => self::getCycleInfos($course, $cycle_date), + 'icon' => $is_start_editable ? '' : 'lock-locked' + ]; + } + + /** + * Creates a string with course infos to be displayed as a tooltip in calendar events + * + * @param SeminarCycleDate $cycle_date + * + * @return string enriched course info string for tooltip + */ + private static function getCycleInfos($course, $cycle_date) + { + + $info_string = $course->getFullName('number-name') . "\n"; + + $dozenten = []; + foreach (CourseMember::findByCourseAndStatus($course->id, 'dozent') as $cmember) { + $dozenten[$cmember->user->user_id] = $cmember->user->getFullName(); + } + if ($dozenten) { + $info_string .= implode(', ', $dozenten) . "\n"; + } + + $rooms = []; + foreach ($cycle_date->getAllDates() as $course_date) { + $room = $course_date->getRoom(); + if ($room) { + $rooms[$room->id] = $room->name; + } + } + if ($rooms) { + $info_string .= implode(', ', $rooms) . "\n"; + } + + if ($course->getSemClass()->offsetGet('module')) { + $mvv_pathes = []; + $course_start = $course->start_time; + $course_end = ($course->end_time < 0 || is_null($course->end_time)) + ? PHP_INT_MAX + : $course->end_time; + // set filter to show only pathes with valid semester data + ModuleManagementModelTreeItem::setObjectFilter('Modul', + function ($modul) use ($course_start, $course_end) { + // check for public status + if (!$GLOBALS['MVV_MODUL']['STATUS']['values'][$modul->stat]['public']) { + return false; + } + $modul_start = Semester::find($modul->start)->beginn ?: 0; + $modul_end = Semester::find($modul->end)->ende ?: PHP_INT_MAX; + return ($modul_start <= $course_end && $modul_end >= $course_start); + } + ); + + ModuleManagementModelTreeItem::setObjectFilter('StgteilVersion', + function ($version) { + return (bool) $GLOBALS['MVV_STGTEILVERSION']['STATUS']['values'][$version->stat]['public']; + } + ); + + $trail_classes = ['Modulteil', 'StgteilabschnittModul', 'StgteilAbschnitt', 'StgteilVersion']; + $mvv_object_pathes = MvvCourse::get($course->getId())->getTrails($trail_classes); + if ($mvv_object_pathes) { + if (Config::get()->COURSE_SEM_TREE_DISPLAY) { + $mvv_tree = []; + foreach ($mvv_object_pathes as $mvv_object_path) { + // show only complete pathes + if (count($mvv_object_path) == 4) { + // flatten the pathes to a linked list + $stg = reset($mvv_object_path); + $parent_id = 'root'; + foreach ($mvv_object_path as $mvv_object) { + $mvv_object_id = $mvv_object instanceof StgteilabschnittModul + ? $mvv_object->modul_id + : $mvv_object->id; + $mvv_tree[$parent_id][$mvv_object_id] = [ + 'id' => $mvv_object_id, + 'name' => $mvv_object->getDisplayName(), + 'class' => get_class($mvv_object), + ]; + $parent_id = $mvv_object_id; + } + } + } + if (count($mvv_tree)) { + // add the root node + $mvv_tree['start'][] = [ + 'id' => 'root', + 'name' => Config::get()->UNI_NAME_CLEAN, + 'class' => '' + ]; + } + } else { + foreach ($mvv_object_pathes as $mvv_object_path) { + // show only complete pathes + if (count($mvv_object_path) == 4) { + $mvv_object_names = []; + $modul_id = ''; + foreach ($mvv_object_path as $mvv_object) { + if ($mvv_object instanceof StgteilabschnittModul) { + $modul_id = $mvv_object->modul_id; + } + $mvv_object_names[] = $mvv_object->getDisplayName(); + } + $mvv_pathes[] = [$modul_id => $mvv_object_names]; + } + } + } + // to prevent collisions of object ids in the tree + // in the case of same objects listed in more than one part + // of the tree + $id_sfx = new stdClass(); + $id_sfx->c = 1; + } + foreach ($mvv_pathes as $mvv_path) { + foreach ($mvv_path as $mvv_path_content) { + $info_string .= implode(' > ', $mvv_path_content) . "\n"; + } + } + } + + return $info_string; + } + + public static function getBackgroundEvents($start = null) + { + $datetime = new DateTime(); + $slot_duration = 1; + $start_time = 8; + $end_time = 16; + $events = []; + $day_interval = 1; + + if ($start == null) { + $datetime->modify('monday this week'); + $datetime->add(new DateInterval('PT' . $start_time . 'H')); + $day_interval = 7; + } + + for ($i = 1; $i <= $day_interval; $i++) { + for ($slot = $start_time; $slot < $end_time; $slot += $slot_duration) { + if ($slot % 2) { + $datetime->setTime($slot, 0); + $events[] = [ + 'start' => self::iso8601date($datetime, $slot), + 'end' => self::iso8601date($datetime, $slot + $slot_duration), + 'rendering' => 'background', + ]; + + } + } + $datetime->setTime($start_time, 0); + $datetime->add(new DateInterval('P1D')); + }; + return $events; + } + + private static function iso8601date($date, $time = '00:00:00', $timezone = '+00:00') + { + // If only date parameter is passed and is a DateTimeInterface object or + // unix timestamp, assume time from date + if (func_num_args() === 1 && ($date instanceof DateTimeInterface || ctype_digit($date))) { + $time = $date; + } + + // Get time + if ($time instanceof DateTimeInterface) { + $time = $time->format('H:i:s'); + } elseif (ctype_digit($time)) { + $time = date('H:i:s', $time); + } elseif (sscanf($time, '%u:%u:%u', $hours, $minutes, $seconds)) { + $time = sprintf('%02u:%02u:%02u', $hours, $minutes, $seconds); + } + + // Get date + if ($date instanceof DateTimeInterface) { + $date = $date->format('Y-m-d'); + } elseif (ctype_digit($date)) { + $date = date('Y-m-d', $date); + } + + return "{$date}T{$time}{$timezone}"; + } + + + // calculates the luminosity of an given RGB color + // the color code must be in the format of RRGGBB + // the luminosity equations are from the WCAG 2 requirements + // http://www.w3.org/TR/WCAG20/#relativeluminancedef + private static function calculateLuminosity($color) + { + $r = hexdec(substr($color, 0, 2)) / 255; // red value + $g = hexdec(substr($color, 2, 2)) / 255; // green value + $b = hexdec(substr($color, 4, 2)) / 255; // blue value + if ($r <= 0.03928) { + $r = $r / 12.92; + } else { + $r = pow(($r + 0.055) / 1.055, 2.4); + } + if ($g <= 0.03928) { + $g = $g / 12.92; + } else { + $g = pow(($g + 0.055) / 1.055, 2.4); + } + if ($b <= 0.03928) { + $b = $b / 12.92; + } else { + $b = pow(($b + 0.055) / 1.055, 2.4); + } + $luminosity = 0.2126 * $r + 0.7152 * $g + 0.0722 * $b; + return $luminosity; + } + + // calculates the luminosity ratio of two colors + // the luminosity ratio equations are from the WCAG 2 requirements + // http://www.w3.org/TR/WCAG20/#contrast-ratiodef + private static function calculateLuminosityRatio($color1, $color2) + { + $c1 = ltrim($color1, '#'); + $c2 = ltrim($color2, '#'); + $l1 = self::calculateLuminosity($c1); + $l2 = self::calculateLuminosity($c2); + if ($l1 > $l2) { + $ratio = ($l1 + 0.05) / ($l2 + 0.05); + } else { + $ratio = ($l2 + 0.05) / ($l1 + 0.05); + } + return $ratio; + } +} |
