diff --git a/.babelrc b/.babelrc deleted file mode 100644 index c6c9efb75d8001d08bbb16daebd9fb6291b838fb..0000000000000000000000000000000000000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ -"presets": ["es2015"] -} \ No newline at end of file diff --git a/css/all-ol-style.less b/css/all-ol-style.less new file mode 100644 index 0000000000000000000000000000000000000000..41a007c06853fb79e6e445543311fc09e2d0c87c --- /dev/null +++ b/css/all-ol-style.less @@ -0,0 +1,3 @@ +@import (inline) "../node_modules/openlayers/dist/ol.css"; +@import "legend"; +@import "ol-popup"; diff --git a/css/glrtoc/glrtoc-opsmap.less b/css/glrtoc/glrtoc-opsmap.less new file mode 100644 index 0000000000000000000000000000000000000000..6e0df6500e34a488e616043f022aeea75e89c88e --- /dev/null +++ b/css/glrtoc/glrtoc-opsmap.less @@ -0,0 +1,132 @@ +@import "../all-ol-style"; +@import "../media-control"; + + +body, html { + height: 100%; + width: 100%; + margin: 0; + padding: 0; +} + +#main-container { + height: 100%; +} + +.flex-container { + display: flex; + + //> div { + // flex-grow: 1; + //} +} + +#map{ + flex-grow: 1; +} + + +#sidebar { + height: 100%; + width: 350px; + flex-grow: initial; + position: relative; +} + +#logo-container { + > div { + flex-grow: 1; + } + + div { + margin: 7px; + height: 150px; + } + + div:first-child { + background: url('img/glrtoc-logo.png') no-repeat center; + background-size: contain; + } + + div:nth-child(2) { + background: url('img/tops-logo.png') no-repeat center; + background-size: contain; + } +} + +#map { + position: relative; +} + +#tabs { + height: 100%; + padding: 0; + border: none; + width: 100%; + + + > div { + padding: 0; + height: 98%; + + p { + text-align: justify; + padding: 7px 12px; + margin: 10px 0; + } + + } + + .ui-tab { + padding: 3px 7px !important; + } +} + +#operations-tab { + h3 { + margin-top: 0; + padding-top: 5px; + padding-bottom: 5px; + } + + > div{ + padding: 0; + } +} + +#hide-sidebar, #show-sidebar { + z-index: 5; + position: absolute; + color: white; + cursor: pointer; +} + +//hide sidebar span +#hide-sidebar { + right: 4px; + top: 9px; +} + +#show-sidebar { + display: none; + left: -12px; + top: 74px; + background: linear-gradient(#74BBD8, #3FA3CA); + width: 40px; + text-align: right; + padding: 10px 4px; + border-radius: 5px; + border: solid #4297D7 1px; +} + +#operations > div { + padding: 0; +} + +#animation-control { + text-align: center; + padding: 10px; +} + + + diff --git a/css/glrtoc/img/glrtoc-logo.png b/css/glrtoc/img/glrtoc-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e703e4220e4f9bfc334eb49e95d19b8e9720aefe Binary files /dev/null and b/css/glrtoc/img/glrtoc-logo.png differ diff --git a/css/glrtoc/img/tops-logo.png b/css/glrtoc/img/tops-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..436dbf5a4ff00a9dcea8dd51add6f68b5943c4f7 Binary files /dev/null and b/css/glrtoc/img/tops-logo.png differ diff --git a/css/itsMap.less b/css/itsMap.less new file mode 100644 index 0000000000000000000000000000000000000000..7cbd153a7077b453bf003a168e0e6907670bed6d --- /dev/null +++ b/css/itsMap.less @@ -0,0 +1,116 @@ +@import "./all-ol-style"; + + +@headerHeight: 80px; + +body, html { + height: 100%; + width: 100%; + margin: 0; + padding: 0; +} + +#header { + height: @headerHeight; + background-color: #808080; + + span { + display: inline-block; + margin: 9px; + font-size: 28px; + line-height: 30px; + } + + a { + float: right; + } + + img { + margin: 3px 10px; + max-height: @headerHeight - 10px; + width: auto; + } +} + +#container { + display: flex; + height: ~"calc(100% - " @headerHeight ~")"; + width: 100%; +} + +#left { + height: 100%; + width: 320px; + overflow-y: auto; +} + +#map { + flex: 1 +} + +.legend-container { + border: none; +} + +@media screen and (max-height: 650px) { + +} + +@media screen and (max-height: 640px), (max-width: 650px) { + + #header a { + display: none; + } + + #header{ + display: none; + } + + #container { + //display: block; + height: 100%; + } + + #left { + width: 246px; + height: auto; + position: absolute; + top: 5px; + right: 5px; + z-index: 10; + background-color: white; + -webkit-border-radius:5px; + -moz-border-radius:5px; + border-radius: 5px; + max-height: 250px; + overflow-y: scroll; + } + + #map{ + height: 100%; + } + + .legend-container ul{ + padding-left: 5px; + } + +} + +@media screen and (max-height: 500px), (max-width: 346px) { + #left{ + width: 204px; + max-height: 204px; + } + + .ol-popup{ + width: 240px; + min-width: 240px; + + iframe{ + width: 240px; + } + } +} + + + diff --git a/css/legend.less b/css/legend.less new file mode 100644 index 0000000000000000000000000000000000000000..504f2813186f2ee31441e54f5d17ede363f69ad4 --- /dev/null +++ b/css/legend.less @@ -0,0 +1,116 @@ +@legendKeyOffset: 7px; + +@rectangleImg: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAATCAMAAAB2tdn3AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAAcHBwoKCgsLCw0NDQ4ODg8PDxAQEBYWFhcXFxsbGxwcHB0dHR4eHh8fHyAgICEhISIiIiQkJCUlJSYmJicnJygoKCkpKSoqKiwsLC0tLS4uLi8vLzAwMDQ0NDU1NTc3Nzg4ODk5OT09PT4+Pj8/P0FBQUJCQkNDQ0REREZGRkdHR0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1FRUVJSUlNTU1RUVFZWVldXV1hYWFlZWVpaWl5eXmBgYGFhYWJiYmRkZGZmZmhoaGlpaWpqam1tbW5ubm9vb3Nzc3V1dXd3d3l5eXx8fH5+fn9/fwCADwGBEQKCEgGJEwKKEwSMFQGRFAKSFAKTFQiXGguUHRifKAynGAipFROjJhukLR+iMSaWNCuVOCGhMSSmND+oTT20SwnQGwzRHRDCJRPDKADjHQDmGgDmGwDlHQHpHwDyFwDzGQD1GAD2GQD3HQD3HgD/HgD/HwLqIAD/IAD/IQD/IkeFTkiFUEiGUFeNXlmPX0SrU0i4VVajX2CpaW2kdF7MbGHPbnyxgoCAgIGBgYKCgoODg4SEhIWFhYiIiImJiYuLi4yMjI6OjpCQkJWVlZiYmJqampubm5ycnImwjI+zkZqomKSkpKampqioqKurq6ysrK2tra6urq+vr6SwogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4rSb8AAAEAdFJOU////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wBT9wclAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGHRFWHRTb2Z0d2FyZQBwYWludC5uZXQgNC4wLjOM5pdQAAAB+UlEQVRIS5WV6VfTQBTFA7YgoICsFtmxgLRShQIqCLKDKEFQ3FlERdlxwwTBBQRMKVqQRdSyCH/n803yevj65ndy8iY55957ZpJ5owDAgdceJkVSE6pMWlPoFRN7yS6qMNSbahlIUJdg1dM1VpXAUSRCL7fQoxQx4hZrDiVpvQjK/kkxajyf7Ujj4Eg/V7WBgp1KgMogDg6/9N7pus3iwcC8yDq1p3hEdRX7Aqs8At9rM9tQEglwHMvSo1eaPs1Dnxp+gpINjxKBpfqqX+Xju5mPGlxfsUZD73QZ3nxGjU0JA1h3Gt8kUI16nGo8wAmAxQlyY6K9+A1wTITWuVZUMmShGhUAcWboU7mJ6vrIJ4BwEVpe4ic7Jv7cUGinRmZMtPFZCvWWLpMbk5WcUGgHmbF5/4FCy2RDj2Z6i7y4aOMzFFrr9kt+07JQaN8UuXEZ/UihP/N8ZMdCNRqvh/7ehUky4zK4Lf5eG26cqmsy+9RoL0BNtLVPX8pN9e0z1NgV7L8AhaXLAW5L+tGUJbo1dqQoLF8fv5boSGP9KPnlVoK4TgA1ZzPTWZzJcJavCcUFvP5h/fO85173XRb3H84JZeJfBdz4geQxTxnzrJDlhlOcp66ETXpmc4XO0+RLVuWzlZJnHuKw67GFS5HYYDkANCfTKyY2VxAA/gOxObo6iNgi8wAAAABJRU5ErkJggg=='); + + +.legend-container { + list-style: none; + border: solid black 1px; + border-radius: 5px; + background-color: rgba(211, 211, 211, 0.2); + margin: 2px; + padding: 2px; + + ul { + list-style: none; + padding-left: 17px; + } + + li { + border-radius: 7px; + margin: 2px; + padding: 2px 4px; + } + + hr { + display: inline-block; + width: 40px; + height: 10px; + background-color: blue; + border: none; + margin: 0 0 3px @legendKeyOffset; + } + + > li:first-child { + font-weight: bold; + min-height: 25px; + + input { + display: none; + } + + input + label { + width: 100px; + height: 19px; + margin: 5px; + display: inline-block; + } + + input + label > span { + display: inline-block; + width: 59px; + height: 19px; + background: @rectangleImg no-repeat 0 0; + } + + + + input:checked + label > span { + background: @rectangleImg no-repeat -59px 0; + } + } +} + + +.legend-layer-subitem { + display: inline-block; + max-width: 148px; + overflow: hidden; + max-height: 20px; +} + +.legend-layer-icon { + margin-left: @legendKeyOffset; +} + +.legend-layer-div li { + margin: 0; + padding-top: 0; + padding-bottom: 0; +} + +.layer-not-visible { + background-color: gray; + display: none; +} + +.layer-force-show { + display: inherit; +} + +.layer-group-expander, .map-server-expander, .unique-symbol-expander, .legend-items-expander { + color: #59AFEE; + cursor: pointer; + padding-left: 4px; + font-size: 14px; +} + +.esri-popup-table{ + border-collapse: collapse; + + td, th { + border: solid black 1px; + padding: 0 4px; + } + + tr:nth-child(even){ + background-color: lightblue; + } +} + +.legend-layer-name, .legend-check{ + cursor: pointer +} + + + diff --git a/css/media-control.less b/css/media-control.less new file mode 100644 index 0000000000000000000000000000000000000000..9233513556e87c5b315d1333e0de9c7c33a1984e --- /dev/null +++ b/css/media-control.less @@ -0,0 +1,68 @@ +@mediaImg: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJEAAAAdCAMAAACddH6yAAAABGdBTUEAALGPC/xhBQAAAwBQTFRFAAAAJycmKygmLCknKSkpKSkqLysqLCwsLS0tLi4uLi8vMCwrMi0sMS8tNCwpMTAvNzAvMDAwMTExMTEyMjIxMjIyMzMzMzM0MzQ0NjExNzMxNDQ0NTU1NTY2Njc3OTMxOTc2PDg2OTk5OTo7PTo5Pz4+Pj8/RDs2R0A9REA+QkNDQkRFR0hIS0NBS0VCTUdES0tLTU5NVFRUVVdYYFlXZl9caF9cYWBgZ2Jham1ubGxsc3JycXR2Zn6HaYCIcpSegHx7hIWFjo+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAptsNGgAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAAIpSURBVFhH7ZdrV9QwEIYriLDgbQsdUfCKchEVBBVUFOH//6c482a627Qz2VVzjl94PiQznZP02TRNz1bhETnUIYRa4wEbXNzUeEAza+S2xgP4ntWqxhb+tEwYaWARGg0sQvaelQYmT7U32dH+z3mmvUktRuu8jgPecmHLK4qNzCuPZ8A7XR+zeMgF+aFm8ZhHNmxkFrER2MgpfohGmvV4JT5ecR9GzrS70cgZGmC0rEmfnBEXmRVN+sBI3hqLOYz8eWcZjTTpk1ujG6PI3Ebj2+g+ob0vTdfomr7EoCUx+jUh5nMa3UO+iraJO6tr1CxI+xw7eemutKlR72clRjAAnbw10qud4sQIbY3WM6rxbtVkGRGNYwyKGBF9lbtJ4hjxAcVG3NpGRA9jxhQyosf4Ul04RhyykbSeEdFlzLlYxojW8O08qA0jKbT4Ru2jK2bUYhh1lXyj5iJeKGY0xhqNrTVawDLNeGrvYyrFMkZ3sI/OvJ29jp3NVxyjzstWyOgIX3SO/+rtxywtRYzQ5s+jcIQTctEyOo+RUsQIeVx4w2h0C91PtHvSJEYPYj8hMerDlalRn6mRQddoSNdowI0R+H9GTvUNjJzij5zRCYyckZ9zRqfRiF5rnsIFNqKXmqbwYSpGLzRN0dP/iaYpXGQj2tY0hQswosZAruOvp+YJM4tA8wS5nh3ZVNMJhuCE90i/zT3+YWSVGft98gAMPuL8d/iWKx7nilfhN6Q1MB5pcaF/AAAAAElFTkSuQmCC'); + +.media-control-container { + padding: 10px; + text-align: center; + + input[type=range]{ + width: 80%; + } + + input[type=range]:disabled{ + cursor: not-allowed; + background-color: lightgray; + } +} + +.media-player-button { + background: @mediaImg no-repeat; + height: 29px; + width: 30px; + display: inline-block; + margin: 0 2px; + cursor: pointer; +} + +.media-player-button:hover { + background-color: lightblue; +} + +.media-pause { + background-position: -86px 0; +} + +.media-play { + background-position: -28px 0; +} + +.media-stop { + background-position: -57px 0; +} + +.media-ahead { + background-position: -116px 0; +} + +.media-back { + background-position: 1px 0; +} + +.media-disabled { + display: none; +} + +.media-locked{ + background-color: lightgray !important; + cursor: not-allowed; +} + +.media-control-value-label-container{ + display: flex; + justify-content: space-between; + + span{ + display: block; + font-size: small; + } +} + diff --git a/css/npmrds-heatmap.less b/css/npmrds-heatmap.less new file mode 100644 index 0000000000000000000000000000000000000000..16ffa8b039e04cf59bfad30c56ebf0b4f931c989 --- /dev/null +++ b/css/npmrds-heatmap.less @@ -0,0 +1,174 @@ +@heatMapControlHeight: 135px; +@heatMapSliderHeight: 30px; +@import "./all-ol-style"; + + +html, body { + height: 100%; + width: 100%; + margin: 0; + /*position: relative;*/ +} + +#container { + display: flex; + height: 100%; + width: 100%; +} + +#map { + flex: 1; +} + +#left { + flex: initial; + width: 300px; + min-width: 100px; + + > div { + margin: 10px; + } +} + +#ul-hwy-dirs { + list-style: none; + padding-left: 5px; + max-height: 300px; + overflow-y: auto; + background-color: lightgrey; + + li { + padding: 2px; + } +} + +h4 { + margin: 10px 5px; +} + +#right { + width: 60%; + height: 100%; + + input[type=button] { + margin: 3px 0; + } +} + +#heat-map-control { + display: flex; + flex-wrap: wrap; + height: @heatMapControlHeight; + + > div { + margin: 0 5px; + } + + ul { + list-style: none; + padding-left: 0; + margin-top: 14px; + } +} + +#heat-slider-container { + height: @heatMapSliderHeight; +} + +#heat-map-slider { + border: none; + width: 95%; + padding: 0; + margin: 0 0 0 18px; +} + +#heatmap-canvas { + position: absolute; + top: 0; + left: 22px; + cursor: crosshair; +} + +#heat-slider-container, #canvas-container { + width: 100%; + position: relative; +} + +#canvas-container { + height: ~"calc(100% - " @heatMapControlHeight + @heatMapSliderHeight ~")"; + overflow-y: auto; +} + +#heat-map-vertical-bar { + position: absolute; + /*z-index: 4;*/ + border-right: solid blue 2px; + left: 22px; + top: 0; + width: 0; + height: 0; + background-color: rgba(100, 100, 100, 0.3); +} + +#date-ul { + list-style: none; + margin: 0; + padding: 0; + position: absolute; + left: 0; + top: 0; + z-index: -5; + + li { + border-bottom: solid #000000 1px; + height: 575px; + } + + li:nth-child(odd) { + background-color: lightblue; + } + + li div { + color: blue; + height: 150px; + transform: rotate(-90deg) translate(-259px, 0px); + transform-origin: left top 0; + float: left; + } +} + +#canvas-tooltip-span { + display: none; + z-index: 100; + position: fixed; + background-color: lightgrey; + border: solid black 1px; + border-radius: 5px; + padding: 5px; + /*height: 50px;*/ + width: 160px; + overflow: hidden; + text-align: center; +} + +#progress-indicator-div { + z-index: 200; + background-color: lightblue; + border: solid darkslategray 1px; + border-radius: 5px; + width: 200px; + padding: 10px; + margin: 20px; + display: none; +} + +#sel-hwy { + padding-left: 14px; + padding-top: 9px; + font-weight: bold; + display: inline-block; +} + +/*.ui-datepicker{*/ +/*z-index: 100 !important;*/ +/*}*/ \ No newline at end of file diff --git a/css/ol-popup.less b/css/ol-popup.less new file mode 100644 index 0000000000000000000000000000000000000000..8e13d3ef8c4902942dd8240840a3f77a60f84fd6 --- /dev/null +++ b/css/ol-popup.less @@ -0,0 +1,68 @@ +.ol-popup { + position: absolute; + background-color: white; + -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); + filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); + padding: 22px 5px 5px 5px; + border-radius: 10px; + border: 1px solid #cccccc; + bottom: 12px; + left: -50px; + min-width: 280px; + cursor: default; +} + +.ol-popup:after, .ol-popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.ol-popup:after { + border-top-color: white; + border-width: 10px; + left: 48px; + margin-left: -10px; +} + +.ol-popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 48px; + margin-left: -11px; +} + +.ol-popup-closer { + text-decoration: none; + position: absolute; + top: 2px; + right: 8px; +} + +.ol-popup-closer:after { + content: "X"; +} + +.ol-popup-nav { + background-color: lightgray; + padding: 3px; + margin-bottom: 7px; +} + +.ol-popup-nav-arrow{ + color: #419CC4; + cursor: pointer; + margin: 0 3px; + font-size: larger; +} + +.ol-inner-inner { + height: 300px; + //width: 392px; + //padding-right: 25px; + overflow-y: auto; +} diff --git a/css/peergroup.less b/css/peergroup.less new file mode 100644 index 0000000000000000000000000000000000000000..e0fb5e7106e18ac9dd306a3168a4534acfc38315 --- /dev/null +++ b/css/peergroup.less @@ -0,0 +1,173 @@ +@import './all-ol-style'; + +@sidebarWidth: 280px; + +html, body { + margin: 0; + padding: 0; + height: 100%; + width: 100%; +} + +#app-container { + display: flex; + height: 100%; + + > div { + height: 100%; + overflow-y: auto; + } +} + +#left-sidebar { + width: @sidebarWidth; + + label { + display: inline-block; + margin-left: 4px; + } + + h6 { + margin-top: 5px; + margin-bottom: 2px; + } +} + +#accordion { + font-size: 0.9em !important; + + h3 { + padding-top: 1px; + padding-bottom: 1px; + margin-bottom: 2px; + } +} + +#right-sidebar { + width: 400px; +} + +#map { + flex: 1; +} + +#dialog{ + display: none; +} +// +.ui-accordion-content { + padding: 5px 10px !important; +} + +select { + margin: 4px; + padding: 0; +} + +input[type=text] { + margin: 2px 7px; + padding: 5px; +} + +.divUnd { + width: 100px; + +} + +.equality-compare { + width: 45px; +} + +.class-adtVal { + width: 90px; +} + +.class-laneVal, .class-speedVal { + width: 50px; +} + +.comma-list { + width: 250px; + +} + +#summary { + border-collapse: collapse; +} + +#summary tr { + height: 30px; +} + +#summary th, td { + border: 1px solid black; + padding: 1px 4px; + text-align: center; + //color: #636363; +} + +.invalid { + border: solid red 1px !important; +} + +.popup-table { + border-collapse: collapse; + margin-top: 5px; + +} + +.popup-table th, td { + border: 1px solid black; +} + +// +//.ol-popup { +// display: none; +// position: absolute; +// background-color: white; +// -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); +// -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); +// filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); +// padding: 15px; +// border-radius: 10px; +// border: 1px solid #cccccc; +// bottom: 12px; +// left: -50px; +//} +// +//.ol-popup:after, .ol-popup:before { +// top: 100%; +// border: solid transparent; +// content: " "; +// height: 0; +// width: 0; +// position: absolute; +// pointer-events: none; +//} +// +//.ol-popup:after { +// border-top-color: white; +// border-width: 10px; +// left: 48px; +// margin-left: -10px; +//} +// +//.ol-popup:before { +// border-top-color: #cccccc; +// border-width: 11px; +// left: 48px; +// margin-left: -11px; +//} +// +//.ol-popup-closer { +// text-decoration: none; +// position: absolute; +// top: 2px; +// right: 8px; +//} +// +//.ol-popup-closer:after { +// content: "✖"; +//} +// +// diff --git a/css/tip-colors.less b/css/tip-colors.less new file mode 100644 index 0000000000000000000000000000000000000000..669e4c57f0c18015eda76686173593d0d5b80086 --- /dev/null +++ b/css/tip-colors.less @@ -0,0 +1,30 @@ +.cell-min { + background-color: #00ff00 !important; +} + +.cell-very-low { + background-color: #55ff00 !important; +} + +.cell-low { + background-color: #aaff00 !important; +} + +.cell-mid { + background-color: #ffff00 !important; +} + +.cell-high { + background-color: #ffaa00 !important; +} + +.cell-very-high { + background-color: #ff5500 !important; + font-weight: bold; +} + +.cell-max { + background-color: #ff0000 !important; + font-weight: bold; + text-decoration: underline; +} \ No newline at end of file diff --git a/css/tip-results.less b/css/tip-results.less new file mode 100644 index 0000000000000000000000000000000000000000..8a04f94700692c9c3a6d0a6b5e24e2b95ec744f7 --- /dev/null +++ b/css/tip-results.less @@ -0,0 +1,136 @@ +@import "tip-colors"; +@import "./all-ol-style"; + +body, html, #container { + height: 100%; + width: 100%; + margin: 0; + padding: 0; +} + +#container, #summary { + display: flex; +} + +#summary { + height: 38%; + + > div { + flex-grow: 1; + height: 100%; + overflow-y: auto; + } +} + +#crash-data { + table { + border-collapse: collapse; + margin: 7px 4px 0 4px; + } + + th, td { + border: solid black 1px; + text-align: center; + padding: 0 5px; + } +} + +#right { + flex: 1; +} + +#map { + height: 60%; + position: relative; +} + +#legend-container { + position: absolute; + width: 250px; + max-height: 80%; + min-height: 30px; + overflow-y: auto; + background-color: rgba(255, 255, 255, 0.8); + z-index: 10; + top: 5px; + right: 5px; + border-radius: 7px; + + > ul { + > li:first-child { + display: none; + } + } +} + +#summary { + h3, h4, ul { + margin: 5px 10px; + } +} + +#results-container { + width: 936px; + padding-right: 20px; + height: 100%; + overflow: auto; + position: relative; + table { + border-collapse: collapse; + margin: 4px; + width: 100%; + //height: 100%; + position: relative; + table-layout: fixed; + + th, td { + border: solid black 1px; + padding: 3px; + text-align: center; + } + + > *{ + width: 100%; + } + + th { + cursor: pointer; + } + + thead { + + display: block; + width: 100%; + + tr { + background-color: #4a4a4a; + color: #FDFDFD; + width: 100%; + } + } + + tbody { + display: block; + height: 400px; + overflow-y: auto; + width: 100%; + } + } +} + +.selectable-row:hover { + background-color: #00ffd0; + cursor: pointer; +} + +.selected-row { + background-color: #0074ff !important; +} + +.score-under-one { + display: none; +} + +#show-all-toggle, #show-all-toggle-label { + cursor: pointer; +} diff --git a/css/tip.less b/css/tip.less new file mode 100644 index 0000000000000000000000000000000000000000..09ac1b59db406b49d1151b8fb966fe131bbba2a3 --- /dev/null +++ b/css/tip.less @@ -0,0 +1,159 @@ +@import "./tip-colors"; +@import "./all-ol-style"; + +html, body { + width: 100%; + height: 100%; + margin: 0; +} + +#container { + display: flex; + height: 100%; + width: 100%; +} + +#left { + overflow-y: scroll; + background-color: lightblue; + height: 100%; + width: 320px; +} + +// suppress first li in legend +.legend-container { + > li:first-child { + display: none; + } +} + +//tip legend style +#tip-segments-layer-li { + display: inherit; + + > div { + height: 80px; + + hr { + height: 4px; + } + + ul:first-of-type { + float: right; + padding-left: 0; + + li { + height: 10px; + } + } + + ul:last-of-type { + float: right; + margin-top: 5px; + + li { + margin: 3px 0; + text-align: right; + border-right: solid black 1px; + border-radius: 0; + } + } + } +} + +//common border styling of legend and preset container +#preset-wrapper, .legend-container { + border: solid black 1px; + border-radius: 5px; +} + +#preset-wrapper { + margin: 3px; + padding: 3px; + border: solid black 1px; + border-radius: 5px; + + h4 { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + } + + select { + width: 141px; + } + + input[type=button] { + width: 88px; + margin: 0; + } +} + +.slider-container { + + > div { + padding: 2px; + border-bottom: solid darkblue 1px; + //min-height: 46px; + } + + label { + display: inline-block; + } + + .slider-label { + width: 97px; + } + + .hidden-select { + display: none; + } + + .percent-label { + padding: 2px 3px; + margin-left: 2px; + background-color: lightgray; + font-weight: bold; + color: orangered; + } + + input[type=range] { + width: 153px; + padding: 1px; + + } + + input[type=range][disabled] { + background-color: #59afee; + cursor: not-allowed; + } + + select { + margin-bottom: 2px; + width: 46px; + } + + .low-high { + font-size: 12px; + } +} + +// offset around show help button +#tip-help { + margin-left: 10px; + margin-top: 4px; +} + +#map { + background-color: slategray; + height: 100%; + flex: 1; + position: relative; +} + +#loading-gif { + left: 10px; + top: 80px; + z-index: 10; + position: absolute; +} diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000000000000000000000000000000000000..8ba80e870929c0a1c86423c4b8b95f2c0f6c185c --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,230 @@ +const gulp = require('gulp'); +const babel = require('gulp-babel'); +const babelify = require('babelify'); +const browserify = require('browserify'); +const buffer = require('vinyl-buffer'); +const source = require('vinyl-source-stream'); +const sourcemaps = require('gulp-sourcemaps'); +const minify = require('gulp-minify'); +const less = require('gulp-less'); +const cssmin = require('gulp-cssmin'); +const rename = require('gulp-rename'); + + +/** + * + * @param {string} inputFile - input file + * @param {string} outputFile - output file + * @param {boolean|*} runMinify - if should minify + * @returns {object} return stream + */ +function processJsFile(inputFile, outputFile, runMinify) { + "use strict"; + runMinify = typeof runMinify == 'boolean' ? runMinify : false; + let pathParts = outputFile.split('/'); + let outFileName = pathParts[pathParts.length - 1]; + pathParts.splice(pathParts.length - 1, 1); + let outDir = pathParts.length === 0 ? '.' : pathParts.join('/'); + + let bundler = browserify({entries: inputFile, "debug": true, "extensions": ["js"]}); + + bundler.transform(babelify.configure({ + presets: ["es2015"], + "ignore": /custom-ol-build|jquery.min/ + })); + + + //bundler.transform(babelify.configure({ + // ignore: /custom-ol-build|jquery.min/ + //})); + //let bundler = browserify({entries: inputFile, extensions: ['.js'], debug: true}) + // .transform(babelify.configure({ + // ignore: /custom-ol-build.js|jquery.min|/, + // presets: ["es2015"], + // extensions: [".ts", ".js"] + // })); + + + //bundler.transform("babelify", {presets: ["es2015"], ignore: /custom-ol-build.js|jquery.min|/}, extensions: ['.js', '.ts']); + + + if (runMinify) { + return bundler.bundle() + .on('error', function (err) { + console.error(err); + }) + .pipe(source(outFileName)) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true})) + .pipe(minify({ + ext: { + src: '-debug.js', + min: '.js' + }, + exclude: ['tasks'], + ignoreFiles: ['.combo.js', '-min.js'] + })) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(outDir)); + } else { + return bundler.bundle() + .on('error', function (err) { + console.error(err); + }) + .pipe(source(outFileName)) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true})) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(outDir)); + } +} + +function processLessFile(inputFile, outputFile) { + "use strict"; + let pathParts = outputFile.split('/'); + let outFileName = pathParts[pathParts.length - 1]; + pathParts.splice(pathParts.length - 1, 1); + let outDir = pathParts.length === 0 ? '.' : pathParts.join('/'); + + let fileNameParts = outFileName.split('.'); + + return gulp.src(inputFile) + .pipe(less().on('error', function (err) { + console.log(err); + })) + .pipe(cssmin().on('error', function (err) { + console.log(err); + })) + .pipe(rename({ + basename: fileNameParts[0], + extname: '.' + fileNameParts[1], + suffix: '.min' + })) + .pipe(gulp.dest(outDir)); +} + +//gulp.task('default', function () { +// "use strict"; +// return gulp.src('src/app.js') +// .pipe(babel()) +// .pipe(gulp.dest('dist')) +//}); + +function _itsInventory(doMinify) { + "use strict"; + //processLessFile('./flaskApp/blueprints/its_inventory/static/css/itsMap.less', './flaskApp/blueprints/its_inventory/static/_build/itsMap.css'); + + return processJsFile('./projects/itsMap.js', './build/itsMap.js', doMinify); +} + +gulp.task('itsInventory-dev', () => { + return _itsInventory(false); +}); + +gulp.task('itsInventory-prod', () => { + return _itsInventory(true); +}); + +function _glrtoc(doMinify) { + "use strict"; + processJsFile('./projects/glrtoc/main.js', './build/glrtoc/main.js', doMinify); + + return processJsFile('./projects/glrtoc/legendTest.js', './build/glrtoc/legendTest.js', doMinify); +} + +gulp.task('glrtoc-dev', () => { + "use strict"; + + return _glrtoc(false); +}); + +gulp.task('glrtoc-prod', () => { + "use strict"; + + return _glrtoc(true); +}); + +function _tsmo(doMinify) { + "use strict"; + processJsFile('./projects/tsmo/legend-test.js', './build/legend-test.js', doMinify); + //processJsFile('./projects/tsmo/slider-test.js', './build/slider-test.js', doMinify); + //processJsFile('./projects/tsmo/main.js', './build/main.js', doMinify); + //return processJsFile('./projects/tsmo/main-report.js', './build/main-report.js', doMinify); +} + +gulp.task('tsmo-dev', () => { + "use strict"; + + return _tsmo(false); +}); + +gulp.task('tsmo-prod', () => { + "use strict"; + + return _tsmo(true); +}); + +function _npmrds(doMinify) { + "use strict"; + + return processJsFile('./flaskApp/blueprints/npmrds/static/js/heatmap/main.js', './flaskApp/blueprints/npmrds/static/_build/heatmap-main.js', doMinify); +} + +gulp.task('npmrds-dev', () => { + "use strict"; + + return _npmrds(false); +}); + +gulp.task('npmrds-prod', () => { + "use strict"; + + return _npmrds(true); +}); + +function _ssa(doMinify) { + "use strict"; + processLessFile('./flaskApp/blueprints/testing/static/css/ssa-corridor.less', './flaskApp/blueprints/testing/static/_build/ssa-corridor.css'); + + return processJsFile('./flaskApp/blueprints/testing/static/js/ssa-main.js', './flaskApp/blueprints/testing/static/_build/ssa-main.js', doMinify); +} + +gulp.task('ssa-dev', () => { + "use strict"; + + return _ssa(false); +}); + +gulp.task('ssa-prod', () => { + "use strict"; + + return _ssa(true); +}); + +gulp.task('peerGroup-dev', () => { + "use strict"; + + return processJsFile('./flaskApp/blueprints/peerGroup/static/js/main.js', './flaskApp/blueprints/peerGroup/static/_build/main.js', false); +}); + +gulp.task('peerGroup-prod', () => { + "use strict"; + + return processJsFile('./flaskApp/blueprints/peerGroup/static/js/main.js', './flaskApp/blueprints/peerGroup/static/_build/main.js', true); +}); + +function _buildTestApps() { + "use strict"; + //processJsFile('./flaskApp/blueprints/testing/static/js/test-custom-build.js', './flaskApp/blueprints/testing/static/_build/test-custom-build.js', false); + + return processJsFile('./flaskApp/blueprints/testing/static/js/test-corridor-layer.js', './flaskApp/blueprints/testing/static/_build/test-corridor-layer.js', false); + +} + +gulp.task('buildTestApps', () => { + "use strict"; + + return _buildTestApps(false); +}); + +gulp.task('build-prod', ['glrtoc-prod', 'tsmo-prod', 'npmrds-prod', 'ssa-prod', 'itsInventory-prod', 'peerGroup-prod']); diff --git a/lib/jquery.floatThead.js b/lib/jquery.floatThead.js new file mode 100644 index 0000000000000000000000000000000000000000..42eba92d4e2345f0efc9ecdbb4c5b56213508749 --- /dev/null +++ b/lib/jquery.floatThead.js @@ -0,0 +1,967 @@ +// @preserve jQuery.floatThead 1.3.2 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2015 Misha Koryak +// @license MIT + +/* @author Misha Koryak + * @projectDescription lock a table header in place while scrolling - without breaking styles or events bound to the header + * + * Dependencies: + * jquery 1.9.0 + [required] OR jquery 1.7.0 + jquery UI core + * + * http://mkoryak.github.io/floatThead/ + * + * Tested on FF13+, Chrome 21+, IE8, IE9, IE10, IE11 + * + */ +let jQuery = require('jQuery'); + +(function( $ ) { + /** + * provides a default config object. You can modify this after including this script if you want to change the init defaults + * @type {Object} + */ + $.floatThead = $.floatThead || {}; + $.floatThead.defaults = { + headerCellSelector: 'tr:visible:first>*:visible', //thead cells are this. + zIndex: 1001, //zindex of the floating thead (actually a container div) + position: 'auto', // 'fixed', 'absolute', 'auto'. auto picks the best for your table scrolling type. + top: 0, //String or function($table) - offset from top of window where the header should not pass above + bottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling + scrollContainer: function($table){ + return $([]); //if the table has horizontal scroll bars then this is the container that has overflow:auto and causes those scroll bars + }, + getSizingRow: function($table, $cols, $fthCells){ // this is only called when using IE, + // override it if the first row of the table is going to contain colgroups (any cell spans greater than one col) + // it should return a jquery object containing a wrapped set of table cells comprising a row that contains no col spans and is visible + return $table.find('tbody tr:visible:first>*:visible'); + }, + floatTableClass: 'floatThead-table', + floatWrapperClass: 'floatThead-wrapper', + floatContainerClass: 'floatThead-container', + copyTableClass: true, //copy 'class' attribute from table into the floated table so that the styles match. + enableAria: false, //will copy header text from the floated header back into the table for screen readers. Might cause the css styling to be off. beware! + autoReflow: false, //(undocumented) - use MutationObserver api to reflow automatically when internal table DOM changes + debug: false //print possible issues (that don't prevent script loading) to console, if console exists. + }; + + var util = window._; + + var canObserveMutations = typeof MutationObserver !== 'undefined'; + + + //browser stuff + var ieVersion = function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a = 1+a,b.innerHTML="<!--[if gt IE "+ a +"]><i><![endif]-->",c[0];);return 4<a?a:document.documentMode}(); + var isFF = /Gecko\//.test(navigator.userAgent); + var isWebkit = /WebKit\//.test(navigator.userAgent); + + //safari 7 (and perhaps others) reports table width to be parent container's width if max-width is set on table. see: https://github.com/mkoryak/floatThead/issues/108 + var isTableWidthBug = function(){ + if(isWebkit) { + var $test = $('<div style="width:0px"><table style="max-width:100%"><tr><th><div style="min-width:100px;">X</div></th></tr></table></div>'); + $("body").append($test); + var ret = ($test.find("table").width() == 0); + $test.remove(); + return ret; + } + return false; + }; + + var createElements = !isFF && !ieVersion; //FF can read width from <col> elements, but webkit cannot + + var $window = $(window); + + /** + * @param debounceMs + * @param cb + */ + function windowResize(eventName, cb){ + if(ieVersion == 8){ //ie8 is crap: https://github.com/mkoryak/floatThead/issues/65 + var winWidth = $window.width(); + var debouncedCb = util.debounce(function(){ + var winWidthNew = $window.width(); + if(winWidth != winWidthNew){ + winWidth = winWidthNew; + cb(); + } + }, 1); + $window.on(eventName, debouncedCb); + } else { + $window.on(eventName, util.debounce(cb, 1)); + } + } + + + function debug(str){ + window && window.console && window.console.error && window.console.error("jQuery.floatThead: " + str); + } + + //returns fractional pixel widths + function getOffsetWidth(el) { + var rect = el.getBoundingClientRect(); + return rect.width || rect.right - rect.left; + } + + /** + * try to calculate the scrollbar width for your browser/os + * @return {Number} + */ + function scrollbarWidth() { + var $div = $( //borrowed from anti-scroll + '<div style="width:50px;height:50px;overflow-y:scroll;' + + 'position:absolute;top:-200px;left:-200px;"><div style="height:100px;width:100%">' + + '</div>' + ); + $('body').append($div); + var w1 = $div.innerWidth(); + var w2 = $('div', $div).innerWidth(); + $div.remove(); + return w1 - w2; + } + /** + * Check if a given table has been datatableized (http://datatables.net) + * @param $table + * @return {Boolean} + */ + function isDatatable($table){ + if($table.dataTableSettings){ + for(var i = 0; i < $table.dataTableSettings.length; i++){ + var table = $table.dataTableSettings[i].nTable; + if($table[0] == table){ + return true; + } + } + } + return false; + } + + function tableWidth($table, $fthCells, isOuter){ + // see: https://github.com/mkoryak/floatThead/issues/108 + var fn = isOuter ? "outerWidth": "width"; + if(isTableWidthBug && $table.css("max-width")){ + var w = 0; + if(isOuter) { + w += parseInt($table.css("borderLeft"), 10); + w += parseInt($table.css("borderRight"), 10); + } + for(var i=0; i < $fthCells.length; i++){ + w += $fthCells.get(i).offsetWidth; + } + return w; + } else { + return $table[fn](); + } + } + $.fn.floatThead = function(map){ + map = map || {}; + if(!util){ //may have been included after the script? lets try to grab it again. + util = window._ || $.floatThead._; + if(!util){ + throw new Error("jquery.floatThead-slim.js requires underscore. You should use the non-lite version since you do not have underscore."); + } + } + + if(ieVersion < 8){ + return this; //no more crappy browser support. + } + + var mObs = null; //mutation observer lives in here if we can use it / make it + + if(util.isFunction(isTableWidthBug)) { + isTableWidthBug = isTableWidthBug(); + } + + if(util.isString(map)){ + var command = map; + var ret = this; + this.filter('table').each(function(){ + var $this = $(this); + var opts = $this.data('floatThead-lazy'); + if(opts){ + $this.floatThead(opts); + } + var obj = $this.data('floatThead-attached'); + if(obj && util.isFunction(obj[command])){ + var r = obj[command](); + if(typeof r !== 'undefined'){ + ret = r; + } + } + }); + return ret; + } + var opts = $.extend({}, $.floatThead.defaults || {}, map); + + $.each(map, function(key, val){ + if((!(key in $.floatThead.defaults)) && opts.debug){ + debug("Used ["+key+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+ (util.keys($.floatThead.defaults)).join(', ')); + } + }); + if(opts.debug){ + var v = $.fn.jquery.split("."); + if(parseInt(v[0], 10) == 1 && parseInt(v[1], 10) <= 7){ + debug("jQuery version "+$.fn.jquery+" detected! This plugin supports 1.8 or better, or 1.7.x with jQuery UI 1.8.24 -> http://jqueryui.com/resources/download/jquery-ui-1.8.24.zip") + } + } + + this.filter(':not(.'+opts.floatTableClass+')').each(function(){ + var floatTheadId = util.uniqueId(); + var $table = $(this); + if($table.data('floatThead-attached')){ + return true; //continue the each loop + } + if(!$table.is('table')){ + throw new Error('jQuery.floatThead must be run on a table element. ex: $("table").floatThead();'); + } + canObserveMutations = opts.autoReflow && canObserveMutations; //option defaults to false! + var $header = $table.children('thead:first'); + var $tbody = $table.children('tbody:first'); + if($header.length == 0 || $tbody.length == 0){ + $table.data('floatThead-lazy', opts); + $table.unbind("reflow").one('reflow', function(){ + $table.floatThead(opts); + }); + return; + } + if($table.data('floatThead-lazy')){ + $table.unbind("reflow"); + } + $table.data('floatThead-lazy', false); + + var headerFloated = true; + var scrollingTop, scrollingBottom; + var scrollbarOffset = {vertical: 0, horizontal: 0}; + var scWidth = scrollbarWidth(); + var lastColumnCount = 0; //used by columnNum() + var $scrollContainer = opts.scrollContainer($table) || $([]); //guard against returned nulls + var locked = $scrollContainer.length > 0; + + var useAbsolutePositioning = null; + if(typeof opts.useAbsolutePositioning !== 'undefined'){ + opts.position = 'auto'; + if(opts.useAbsolutePositioning){ + opts.position = opts.useAbsolutePositioning ? 'absolute' : 'fixed'; + } + debug("option 'useAbsolutePositioning' has been removed in v1.3.0, use `position:'"+opts.position+"'` instead. See docs for more info: http://mkoryak.github.io/floatThead/#options") + } + if(typeof opts.scrollingTop !== 'undefined'){ + opts.top = opts.scrollingTop; + debug("option 'scrollingTop' has been renamed to 'top' in v1.3.0. See docs for more info: http://mkoryak.github.io/floatThead/#options"); + } + if(typeof opts.scrollingBottom !== 'undefined'){ + opts.bottom = opts.scrollingBottom; + debug("option 'scrollingBottom' has been renamed to 'bottom' in v1.3.0. See docs for more info: http://mkoryak.github.io/floatThead/#options"); + } + + + if (opts.position == 'auto') { + useAbsolutePositioning = null; + } else if (opts.position == 'fixed') { + useAbsolutePositioning = false; + } else if (opts.position == 'absolute'){ + useAbsolutePositioning = true; + } else if (opts.debug) { + debug('Invalid value given to "position" option, valid is "fixed", "absolute" and "auto". You passed: ', opts.position); + } + + if(useAbsolutePositioning == null){ //defaults: locked=true, !locked=false + useAbsolutePositioning = locked; + } + var $caption = $table.find("caption"); + var haveCaption = $caption.length == 1; + if(haveCaption){ + var captionAlignTop = ($caption.css("caption-side") || $caption.attr("align") || "top") === "top"; + } + + var $fthGrp = $('<fthfoot style="display:table-footer-group;border-spacing:0;height:0;border-collapse:collapse;visibility:hidden"/>'); + + var wrappedContainer = false; //used with absolute positioning enabled. did we need to wrap the scrollContainer/table with a relative div? + var $wrapper = $([]); //used when absolute positioning enabled - wraps the table and the float container + var absoluteToFixedOnScroll = ieVersion <= 9 && !locked && useAbsolutePositioning; //on IE using absolute positioning doesn't look good with window scrolling, so we change position to fixed on scroll, and then change it back to absolute when done. + var $floatTable = $("<table/>"); + var $floatColGroup = $("<colgroup/>"); + var $tableColGroup = $table.children('colgroup:first'); + var existingColGroup = true; + if($tableColGroup.length == 0){ + $tableColGroup = $("<colgroup/>"); + existingColGroup = false; + } + var $fthRow = $('<fthtr style="display:table-row;border-spacing:0;height:0;border-collapse:collapse"/>'); //created unstyled elements (used for sizing the table because chrome can't read <col> width) + var $floatContainer = $('<div style="overflow: hidden;" aria-hidden="true"></div>'); + var floatTableHidden = false; //this happens when the table is hidden and we do magic when making it visible + var $newHeader = $("<thead/>"); + var $sizerRow = $('<tr class="size-row"/>'); + var $sizerCells = $([]); + var $tableCells = $([]); //used for sizing - either $sizerCells or $tableColGroup cols. $tableColGroup cols are only created in chrome for borderCollapse:collapse because of a chrome bug. + var $headerCells = $([]); + var $fthCells = $([]); //created elements + + $newHeader.append($sizerRow); + $table.prepend($tableColGroup); + if(createElements){ + $fthGrp.append($fthRow); + $table.append($fthGrp); + } + + $floatTable.append($floatColGroup); + $floatContainer.append($floatTable); + if(opts.copyTableClass){ + $floatTable.attr('class', $table.attr('class')); + } + $floatTable.attr({ //copy over some deprecated table attributes that people still like to use. Good thing people don't use colgroups... + 'cellpadding': $table.attr('cellpadding'), + 'cellspacing': $table.attr('cellspacing'), + 'border': $table.attr('border') + }); + var tableDisplayCss = $table.css('display'); + $floatTable.css({ + 'borderCollapse': $table.css('borderCollapse'), + 'border': $table.css('border'), + 'display': tableDisplayCss + }); + if(tableDisplayCss == 'none'){ + floatTableHidden = true; + } + + $floatTable.addClass(opts.floatTableClass).css({'margin': 0, 'border-bottom-width': 0}); //must have no margins or you won't be able to click on things under floating table + + if(useAbsolutePositioning){ + var makeRelative = function($container, alwaysWrap){ + var positionCss = $container.css('position'); + var relativeToScrollContainer = (positionCss == "relative" || positionCss == "absolute"); + var $containerWrap = $container; + if(!relativeToScrollContainer || alwaysWrap){ + var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')}; + $floatContainer.css(css); + $containerWrap = $container.data('floatThead-containerWrap') || $container.wrap("<div class='"+opts.floatWrapperClass+"' style='position: relative; clear:both;'></div>").parent(); + $container.data('floatThead-containerWrap', $containerWrap); //multiple tables inside one scrolling container - #242 + wrappedContainer = true; + } + return $containerWrap; + }; + if(locked){ + $wrapper = makeRelative($scrollContainer, true); + $wrapper.prepend($floatContainer); + } else { + $wrapper = makeRelative($table); + $table.before($floatContainer); + } + } else { + $table.before($floatContainer); + } + + + $floatContainer.css({ + position: useAbsolutePositioning ? 'absolute' : 'fixed', + marginTop: 0, + top: useAbsolutePositioning ? 0 : 'auto', + zIndex: opts.zIndex + }); + $floatContainer.addClass(opts.floatContainerClass); + updateScrollingOffsets(); + + var layoutFixed = {'table-layout': 'fixed'}; + var layoutAuto = {'table-layout': $table.css('tableLayout') || 'auto'}; + var originalTableWidth = $table[0].style.width || ""; //setting this to auto is bad: #70 + var originalTableMinWidth = $table.css('minWidth') || ""; + + function eventName(name){ + return name+'.fth-'+floatTheadId+'.floatTHead' + } + + function setHeaderHeight(){ + var headerHeight = 0; + $header.children("tr:visible").each(function(){ + headerHeight += $(this).outerHeight(true); + }); + if($table.css('border-collapse') == 'collapse') { + var tableBorderTopHeight = parseInt($table.css('border-top-width'), 10); + var cellBorderTopHeight = parseInt($table.find("thead tr:first").find(">*:first").css('border-top-width'), 10); + if(tableBorderTopHeight > cellBorderTopHeight) { + headerHeight -= (tableBorderTopHeight / 2); //id love to see some docs where this magic recipe is found.. + } + } + $sizerRow.outerHeight(headerHeight); + $sizerCells.outerHeight(headerHeight); + } + + + function setFloatWidth(){ + var tw = tableWidth($table, $fthCells, true); + var width = $scrollContainer.width() || tw; + var floatContainerWidth = $scrollContainer.css("overflow-y") != 'hidden' ? width - scrollbarOffset.vertical : width; + $floatContainer.width(floatContainerWidth); + if(locked){ + var percent = 100 * tw / (floatContainerWidth); + $floatTable.css('width', percent+'%'); + } else { + $floatTable.outerWidth(tw); + } + } + + function updateScrollingOffsets(){ + scrollingTop = (util.isFunction(opts.top) ? opts.top($table) : opts.top) || 0; + scrollingBottom = (util.isFunction(opts.bottom) ? opts.bottom($table) : opts.bottom) || 0; + } + + /** + * get the number of columns and also rebuild resizer rows if the count is different than the last count + */ + function columnNum(){ + var count; + var $headerColumns = $header.find(opts.headerCellSelector); + if(existingColGroup){ + count = $tableColGroup.find('col').length; + } else { + count = 0; + $headerColumns.each(function () { + count += parseInt(($(this).attr('colspan') || 1), 10); + }); + } + if(count != lastColumnCount){ + lastColumnCount = count; + var cells = [], cols = [], psuedo = [], content; + for(var x = 0; x < count; x++){ + if (opts.enableAria && (content = $headerColumns.eq(x).text()) ) { + cells.push('<th scope="col" class="floatThead-col">' + content + '</th>'); + } else { + cells.push('<th class="floatThead-col"/>'); + } + cols.push('<col/>'); + psuedo.push("<fthtd style='display:table-cell;height:0;width:auto;'/>"); + } + + cols = cols.join(''); + cells = cells.join(''); + + if(createElements){ + psuedo = psuedo.join(''); + $fthRow.html(psuedo); + $fthCells = $fthRow.find('fthtd'); + } + + $sizerRow.html(cells); + $sizerCells = $sizerRow.find("th"); + if(!existingColGroup){ + $tableColGroup.html(cols); + } + $tableCells = $tableColGroup.find('col'); + $floatColGroup.html(cols); + $headerCells = $floatColGroup.find("col"); + + } + return count; + } + + function refloat(){ //make the thing float + if(!headerFloated){ + headerFloated = true; + if(useAbsolutePositioning){ //#53, #56 + var tw = tableWidth($table, $fthCells, true); + var wrapperWidth = $wrapper.width(); + if(tw > wrapperWidth){ + $table.css('minWidth', tw); + } + } + $table.css(layoutFixed); + $floatTable.css(layoutFixed); + $floatTable.append($header); //append because colgroup must go first in chrome + $tbody.before($newHeader); + setHeaderHeight(); + } + } + function unfloat(){ //put the header back into the table + if(headerFloated){ + headerFloated = false; + if(useAbsolutePositioning){ //#53, #56 + $table.width(originalTableWidth); + } + $newHeader.detach(); + $table.prepend($header); + $table.css(layoutAuto); + $floatTable.css(layoutAuto); + $table.css('minWidth', originalTableMinWidth); //this looks weird, but it's not a bug. Think about it!! + $table.css('minWidth', tableWidth($table, $fthCells)); //#121 + } + } + var isHeaderFloatingLogical = false; //for the purpose of this event, the header is/isnt floating, even though the element + //might be in some other state. this is what the header looks like to the user + function triggerFloatEvent(isFloating){ + if(isHeaderFloatingLogical != isFloating){ + isHeaderFloatingLogical = isFloating; + $table.triggerHandler("floatThead", [isFloating, $floatContainer]) + } + } + function changePositioning(isAbsolute){ + if(useAbsolutePositioning != isAbsolute){ + useAbsolutePositioning = isAbsolute; + $floatContainer.css({ + position: useAbsolutePositioning ? 'absolute' : 'fixed' + }); + } + } + function getSizingRow($table, $cols, $fthCells, ieVersion){ + if(createElements){ + return $fthCells; + } else if(ieVersion) { + return opts.getSizingRow($table, $cols, $fthCells); + } else { + return $cols; + } + } + + /** + * returns a function that updates the floating header's cell widths. + * @return {Function} + */ + function reflow(){ + var i; + var numCols = columnNum(); //if the tables columns changed dynamically since last time (datatables), rebuild the sizer rows and get a new count + + return function(){ + $tableCells = $tableColGroup.find('col'); + var $rowCells = getSizingRow($table, $tableCells, $fthCells, ieVersion); + + if($rowCells.length == numCols && numCols > 0){ + if(!existingColGroup){ + for(i=0; i < numCols; i++){ + $tableCells.eq(i).css('width', ''); + } + } + unfloat(); + var widths = []; + for(i=0; i < numCols; i++){ + widths[i] = getOffsetWidth($rowCells.get(i)); + } + for(i=0; i < numCols; i++){ + $headerCells.eq(i).width(widths[i]); + $tableCells.eq(i).width(widths[i]); + } + refloat(); + } else { + $floatTable.append($header); + $table.css(layoutAuto); + $floatTable.css(layoutAuto); + setHeaderHeight(); + } + $table.triggerHandler("reflowed", [$floatContainer]); + }; + } + + function floatContainerBorderWidth(side){ + var border = $scrollContainer.css("border-"+side+"-width"); + var w = 0; + if (border && ~border.indexOf('px')) { + w = parseInt(border, 10); + } + return w; + } + /** + * first performs initial calculations that we expect to not change when the table, window, or scrolling container are scrolled. + * returns a function that calculates the floating container's top and left coords. takes into account if we are using page scrolling or inner scrolling + * @return {Function} + */ + function calculateFloatContainerPosFn(){ + var scrollingContainerTop = $scrollContainer.scrollTop(); + + //this floatEnd calc was moved out of the returned function because we assume the table height doesn't change (otherwise we must reinit by calling calculateFloatContainerPosFn) + var floatEnd; + var tableContainerGap = 0; + var captionHeight = haveCaption ? $caption.outerHeight(true) : 0; + var captionScrollOffset = captionAlignTop ? captionHeight : -captionHeight; + + var floatContainerHeight = $floatContainer.height(); + var tableOffset = $table.offset(); + var tableLeftGap = 0; //can be caused by border on container (only in locked mode) + var tableTopGap = 0; + if(locked){ + var containerOffset = $scrollContainer.offset(); + tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop; + if(haveCaption && captionAlignTop){ + tableContainerGap += captionHeight; + } + tableLeftGap = floatContainerBorderWidth('left'); + tableTopGap = floatContainerBorderWidth('top'); + tableContainerGap -= tableTopGap; + } else { + floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal; + } + var windowTop = $window.scrollTop(); + var windowLeft = $window.scrollLeft(); + var scrollContainerLeft = $scrollContainer.scrollLeft(); + + return function(eventType){ + var isTableHidden = $table[0].offsetWidth <= 0 && $table[0].offsetHeight <= 0; + if(!isTableHidden && floatTableHidden) { + floatTableHidden = false; + setTimeout(function(){ + $table.triggerHandler("reflow"); + }, 1); + return null; + } + if(isTableHidden){ //it's hidden + floatTableHidden = true; + if(!useAbsolutePositioning){ + return null; + } + } + + if(eventType == 'windowScroll'){ + windowTop = $window.scrollTop(); + windowLeft = $window.scrollLeft(); + } else if(eventType == 'containerScroll'){ + scrollingContainerTop = $scrollContainer.scrollTop(); + scrollContainerLeft = $scrollContainer.scrollLeft(); + } else if(eventType != 'init') { + windowTop = $window.scrollTop(); + windowLeft = $window.scrollLeft(); + scrollingContainerTop = $scrollContainer.scrollTop(); + scrollContainerLeft = $scrollContainer.scrollLeft(); + } + if(isWebkit && (windowTop < 0 || windowLeft < 0)){ //chrome overscroll effect at the top of the page - breaks fixed positioned floated headers + return; + } + + if(absoluteToFixedOnScroll){ + if(eventType == 'windowScrollDone'){ + changePositioning(true); //change to absolute + } else { + changePositioning(false); //change to fixed + } + } else if(eventType == 'windowScrollDone'){ + return null; //event is fired when they stop scrolling. ignore it if not 'absoluteToFixedOnScroll' + } + + tableOffset = $table.offset(); + if(haveCaption && captionAlignTop){ + tableOffset.top += captionHeight; + } + var top, left; + var tableHeight = $table.outerHeight(); + + if(locked && useAbsolutePositioning){ //inner scrolling, absolute positioning + if (tableContainerGap >= scrollingContainerTop) { + var gap = tableContainerGap - scrollingContainerTop + tableTopGap; + top = gap > 0 ? gap : 0; + triggerFloatEvent(false); + } else { + top = wrappedContainer ? tableTopGap : scrollingContainerTop; + //headers stop at the top of the viewport + triggerFloatEvent(true); + } + left = tableLeftGap; + } else if(!locked && useAbsolutePositioning) { //window scrolling, absolute positioning + if(windowTop > floatEnd + tableHeight + captionScrollOffset){ + top = tableHeight - floatContainerHeight + captionScrollOffset; //scrolled past table + } else if (tableOffset.top >= windowTop + scrollingTop) { + top = 0; //scrolling to table + unfloat(); + triggerFloatEvent(false); + } else { + top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0); + refloat(); //scrolling within table. header floated + triggerFloatEvent(true); + } + left = 0; + } else if(locked && !useAbsolutePositioning){ //inner scrolling, fixed positioning + if (tableContainerGap > scrollingContainerTop || scrollingContainerTop - tableContainerGap > tableHeight) { + top = tableOffset.top - windowTop; + unfloat(); + triggerFloatEvent(false); + } else { + top = tableOffset.top + scrollingContainerTop - windowTop - tableContainerGap; + refloat(); + triggerFloatEvent(true); + //headers stop at the top of the viewport + } + left = tableOffset.left + scrollContainerLeft - windowLeft; + } else if(!locked && !useAbsolutePositioning) { //window scrolling, fixed positioning + if(windowTop > floatEnd + tableHeight + captionScrollOffset){ + top = tableHeight + scrollingTop - windowTop + floatEnd + captionScrollOffset; + //scrolled past the bottom of the table + } else if (tableOffset.top > windowTop + scrollingTop) { + top = tableOffset.top - windowTop; + refloat(); + triggerFloatEvent(false); //this is a weird case, the header never gets unfloated and i have no no way to know + //scrolled past the top of the table + } else { + //scrolling within the table + top = scrollingTop; + triggerFloatEvent(true); + } + left = tableOffset.left - windowLeft; + } + return {top: top, left: left}; + }; + } + /** + * returns a function that caches old floating container position and only updates css when the position changes + * @return {Function} + */ + function repositionFloatContainerFn(){ + var oldTop = null; + var oldLeft = null; + var oldScrollLeft = null; + return function(pos, setWidth, setHeight){ + if(pos != null && (oldTop != pos.top || oldLeft != pos.left)){ + $floatContainer.css({ + top: pos.top, + left: pos.left + }); + oldTop = pos.top; + oldLeft = pos.left; + } + if(setWidth){ + setFloatWidth(); + } + if(setHeight){ + setHeaderHeight(); + } + var scrollLeft = $scrollContainer.scrollLeft(); + if(!useAbsolutePositioning || oldScrollLeft != scrollLeft){ + $floatContainer.scrollLeft(scrollLeft); + oldScrollLeft = scrollLeft; + } + } + } + + /** + * checks if THIS table has scrollbars, and finds their widths + */ + function calculateScrollBarSize(){ //this should happen after the floating table has been positioned + if($scrollContainer.length){ + if($scrollContainer.data().perfectScrollbar){ + scrollbarOffset = {horizontal:0, vertical:0}; + } else { + var sw = $scrollContainer.width(), sh = $scrollContainer.height(), th = $table.height(), tw = tableWidth($table, $fthCells); + var offseth = sw < tw ? scWidth : 0; + var offsetv = sh < th ? scWidth : 0; + scrollbarOffset.horizontal = sw - offsetv < tw ? scWidth : 0; + scrollbarOffset.vertical = sh - offseth < th ? scWidth : 0; + } + } + } + //finish up. create all calculation functions and bind them to events + calculateScrollBarSize(); + + var flow; + + var ensureReflow = function(){ + flow = reflow(); + flow(); + }; + + ensureReflow(); + + var calculateFloatContainerPos = calculateFloatContainerPosFn(); + var repositionFloatContainer = repositionFloatContainerFn(); + + repositionFloatContainer(calculateFloatContainerPos('init'), true); //this must come after reflow because reflow changes scrollLeft back to 0 when it rips out the thead + + var windowScrollDoneEvent = util.debounce(function(){ + repositionFloatContainer(calculateFloatContainerPos('windowScrollDone'), false); + }, 1); + + var windowScrollEvent = function(){ + repositionFloatContainer(calculateFloatContainerPos('windowScroll'), false); + if(absoluteToFixedOnScroll){ + windowScrollDoneEvent(); + } + }; + var containerScrollEvent = function(){ + repositionFloatContainer(calculateFloatContainerPos('containerScroll'), false); + }; + + + var windowResizeEvent = function(){ + if($table.is(":hidden")){ + return; + } + updateScrollingOffsets(); + calculateScrollBarSize(); + ensureReflow(); + calculateFloatContainerPos = calculateFloatContainerPosFn(); + repositionFloatContainer = repositionFloatContainerFn(); + repositionFloatContainer(calculateFloatContainerPos('resize'), true, true); + }; + var reflowEvent = util.debounce(function(){ + if($table.is(":hidden")){ + return; + } + calculateScrollBarSize(); + updateScrollingOffsets(); + ensureReflow(); + calculateFloatContainerPos = calculateFloatContainerPosFn(); + repositionFloatContainer(calculateFloatContainerPos('reflow'), true); + }, 1); + if(locked){ //internal scrolling + if(useAbsolutePositioning){ + $scrollContainer.on(eventName('scroll'), containerScrollEvent); + } else { + $scrollContainer.on(eventName('scroll'), containerScrollEvent); + $window.on(eventName('scroll'), windowScrollEvent); + } + } else { //window scrolling + $window.on(eventName('scroll'), windowScrollEvent); + } + + $window.on(eventName('load'), reflowEvent); //for tables with images + + windowResize(eventName('resize'), windowResizeEvent); + $table.on('reflow', reflowEvent); + if(isDatatable($table)){ + $table + .on('filter', reflowEvent) + .on('sort', reflowEvent) + .on('page', reflowEvent); + } + + $window.on(eventName('shown.bs.tab'), reflowEvent); // people cant seem to figure out how to use this plugin with bs3 tabs... so this :P + $window.on(eventName('tabsactivate'), reflowEvent); // same thing for jqueryui + + + if (canObserveMutations) { + var mutationElement = null; + if(util.isFunction(opts.autoReflow)){ + mutationElement = opts.autoReflow($table, $scrollContainer) + } + if(!mutationElement) { + mutationElement = $scrollContainer.length ? $scrollContainer[0] : $table[0] + } + mObs = new MutationObserver(function(e){ + var wasTableRelated = function(nodes){ + return nodes && nodes[0] && (nodes[0].nodeName == "THEAD" || nodes[0].nodeName == "TD"|| nodes[0].nodeName == "TH"); + }; + for(var i=0; i < e.length; i++){ + if(!(wasTableRelated(e[i].addedNodes) || wasTableRelated(e[i].removedNodes))){ + reflowEvent(); + break; + } + } + }); + mObs.observe(mutationElement, { + childList: true, + subtree: true + }); + } + + //attach some useful functions to the table. + $table.data('floatThead-attached', { + destroy: function(){ + var ns = '.fth-'+floatTheadId; + unfloat(); + $table.css(layoutAuto); + $tableColGroup.remove(); + createElements && $fthGrp.remove(); + if($newHeader.parent().length){ //only if it's in the DOM + $newHeader.replaceWith($header); + } + if(canObserveMutations){ + mObs.disconnect(); + mObs = null; + } + $table.off('reflow reflowed'); + $scrollContainer.off(ns); + if (wrappedContainer) { + if ($scrollContainer.length) { + $scrollContainer.unwrap(); + } + else { + $table.unwrap(); + } + } + if(locked){ + $scrollContainer.data('floatThead-containerWrap', false); + } else { + $table.data('floatThead-containerWrap', false); + } + $table.css('minWidth', originalTableMinWidth); + $floatContainer.remove(); + $table.data('floatThead-attached', false); + $window.off(ns); + }, + reflow: function(){ + reflowEvent(); + }, + setHeaderHeight: function(){ + setHeaderHeight(); + }, + getFloatContainer: function(){ + return $floatContainer; + }, + getRowGroups: function(){ + if(headerFloated){ + return $floatContainer.find('>table>thead').add($table.children("tbody,tfoot")); + } else { + return $table.children("thead,tbody,tfoot"); + } + } + }); + }); + return this; + }; +})(jQuery); + +/* jQuery.floatThead.utils - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak + * License: MIT + * + * This file is required if you do not use underscore in your project and you want to use floatThead. + * It contains functions from underscore that the plugin uses. + * + * YOU DON'T NEED TO INCLUDE THIS IF YOU ALREADY INCLUDE UNDERSCORE! + * + */ + +(function($){ + + $.floatThead = $.floatThead || {}; + + $.floatThead._ = window._ || (function(){ + var that = {}; + var hasOwnProperty = Object.prototype.hasOwnProperty, isThings = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp']; + that.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + that.keys = function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (that.has(obj, key)) keys.push(key); + return keys; + }; + var idCounter = 0; + that.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + $.each(isThings, function(){ + var name = this; + that['is' + name] = function(obj) { + return Object.prototype.toString.call(obj) == '[object ' + name + ']'; + }; + }); + that.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + return function() { + context = this; + args = arguments; + timestamp = new Date(); + var later = function() { + var last = (new Date()) - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) result = func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) result = func.apply(context, args); + return result; + }; + }; + return that; + })(); +})(jQuery); + +export default undefined; \ No newline at end of file diff --git a/package.json b/package.json index df446ff00c4d4b8c771fcbdceee169911de38e0a..bef02ff148d8e986135115f659a812abf0e2f16e 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,34 @@ "author": "TOPS Lab", "license": "ISC", "devDependencies": { + "angular2": "^2.0.0-beta.17", + "babel-cli": "^6.8.0", "babel-preset-es2015": "^6.6.0", - "openlayers": "^3.15.1" + "babelify": "^7.3.0", + "browserify": "^13.0.0", + "es6-mixins": "^1.0.2", + "es6-shim": "^0.35.0", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-cssmin": "^0.1.7", + "gulp-less": "^3.0.5", + "gulp-minify": "0.0.11", + "gulp-rename": "^1.2.2", + "gulp-sourcemaps": "^2.0.0-alpha", + "jquery": "^2.2.3", + "jquery-ui": "^1.10.5", + "openlayers": "^3.15.1", + "reflect-metadata": "^0.1.2", + "rxjs": "^5.0.0-beta.6", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0", + "zone.js": "^0.6.12" }, "repository": { "type": "git", "url": "https://github.com/glennvorhes/webmapsjs.git" + }, + "dependencies": { + "angular2": "^2.0.0-beta.17" } } diff --git a/projects/glrtoc/appConfig.js b/projects/glrtoc/appConfig.js new file mode 100644 index 0000000000000000000000000000000000000000..bc44356dede6665076d4b7e70bd8e8694e33fd4c --- /dev/null +++ b/projects/glrtoc/appConfig.js @@ -0,0 +1,150 @@ +/** + * Created by gavorhes on 12/8/2015. + */ + +import mapPopup from '../../src/olHelpers/mapPopup'; +import $ from '../../src/jquery'; +let homeTabId = 'home-tab'; +let coordinationTabId = 'coordination-tab'; +let operationsTabId = 'operations-tab'; + +let operationsStaticPanelId = 'operations-static'; +let operationsAnimatedPanelId = 'operations-animated'; + +class AppConfig { + /** + * app configuration object + */ + constructor() { + this.$opsAccordion = $("#" + operationsTabId); + this.debug = true; + this.map = undefined; + this._coordinationLayer = undefined; + this.lyrIds = []; + this.lyrLookup = {}; + this.lyrArray = []; + this.mediaControl = undefined; + this.animationLayers = []; + this.coordinationLayerId = 'coorindation-layer'; + + /** + * + * @type {Array<LayerBase>} + */ + this.operationsLayersStatic = []; + + /** + * + * @type {Array<LayerBase>} + */ + this.operationsLayersAnimated = []; + + this.currentOperationsLayers = this.operationsLayersStatic; + } + + init() { + for (let l of this.operationsLayersStatic) { + this.map.removeLayer(l['olLayer']); + } + + for (let l of this.operationsLayersAnimated) { + this.map.removeLayer(l['olLayer']); + } + + this.currentTabId = homeTabId; + } + + /** + * Add the layer to the config object + * @param {LayerBase|*} lyr - base layer + */ + _addLayer(lyr) { + this.lyrIds.push(lyr.id); + this.lyrLookup[lyr.id] = lyr; + this.lyrArray.push(lyr); + } + + get coordinationLayer() { + return this._coordinationLayer; + } + + set coordinationLayer(coordLayer) { + this._coordinationLayer = coordLayer; + this._addLayer(coordLayer); + } + + addOperationsLayerStatic(lyr) { + this.operationsLayersStatic.push(lyr); + this._addLayer(lyr); + } + + addOperationsLayerAnimate(lyr) { + this.operationsLayersAnimated.push(lyr); + this._addLayer(lyr); + } + + set currentTabId(tabId) { + mapPopup.closePopup(); + this.mediaControl.stopPlaying(); + if (tabId == operationsTabId) { + for (let l of this.currentOperationsLayers) { + this.map.addLayer(l['olLayer']); + } + } else { + for (let l of this.currentOperationsLayers) { + this.map.removeLayer(l['olLayer']); + } + } + + switch (tabId) { + case homeTabId: + this.coordinationLayer.visible = false; + break; + case coordinationTabId: + this.coordinationLayer.visible = true; + break; + case operationsTabId: + this.coordinationLayer.visible = false; + this.$opsAccordion.accordion("refresh"); + break; + default: + throw tabId + ' tab id not found' + } + } + + set currentOperationsPanelId(panelId) { + mapPopup.closePopup(); + this.mediaControl.stopPlaying(); + + for (let l of this.currentOperationsLayers) { + this.map.removeLayer(l['olLayer']); + } + + switch (panelId) { + case operationsStaticPanelId: + this.currentOperationsLayers = this.operationsLayersStatic; + break; + + case operationsAnimatedPanelId: + this.currentOperationsLayers = this.operationsLayersAnimated; + break; + default: + throw panelId + ' panel not found'; + } + for (let l of this.currentOperationsLayers) { + this.map.addLayer(l['olLayer']); + } + + } + + ///** + // * trick to trigger the map move event + // */ + //forceRefresh() { + // if (this.map) { + // this.map.getView().setZoom(this.map.getView().getZoom()); + // } + //} +} + +export default new AppConfig(); diff --git a/projects/glrtoc/layerPopups.js b/projects/glrtoc/layerPopups.js new file mode 100644 index 0000000000000000000000000000000000000000..4362c1cf8e9be7d5a1d3cd3e7f3f5601004363a8 --- /dev/null +++ b/projects/glrtoc/layerPopups.js @@ -0,0 +1,37 @@ +/** + * Created by gavorhes on 12/7/2015. + */ + + +/** + * coordination layer popup config + * @param {object} props + * @returns {string} + */ +export function coordination(props) { + "use strict"; + return `<iframe src="${window.location.href.replace('#', '') + + '/../toc?toc=' + props['toc']}" width="368" height="292"></iframe>`; +} + +/** + * wrs layer popup config + * @param {object} props + * @returns {string} + */ +export function wrs(props) { + "use strict"; + return `<p style="text-align: center">${props['WMS_INFO'].replace(/\n/g, '<br>')}</p>` +} + +export function specialEventWorkZone(props) { + "use strict"; + let startDate = new Date(props['EventStartDate']); + let endDate = new Date(props['EventEndDate']); + let theContent = '<p style="text-align:center">'; + theContent += props['EventDescription'] + '<br>'; + theContent += `${props['HwyName']} ${props['Location']}` + '<br>'; + theContent += `${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()}`; + theContent += '</p>'; + return theContent; +} diff --git a/projects/glrtoc/layerStyles.js b/projects/glrtoc/layerStyles.js new file mode 100644 index 0000000000000000000000000000000000000000..7b2eaed96ac0a82e79fa30377741b8aea787e63d --- /dev/null +++ b/projects/glrtoc/layerStyles.js @@ -0,0 +1,39 @@ +/** + * Created by gavorhes on 12/3/2015. + */ +import ol from '../../src/custom-ol'; + +export const workZoneAndEventStyle = new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'red', + width: 7 + }), + image: new ol.style.Circle({ + radius: 8, + fill: new ol.style.Fill({ + color: 'magenta' + }), + stroke: new ol.style.Stroke({ + color: 'magenta' + }) + }) +}); + +export function wrsStyle(feature, resolution) { + let colorString = feature.getProperties()['COLOR']; + + let c; + if (typeof colorString === 'string') { + c = colorString.split(' '); + } else { + c = [125, 125, 125]; + } + + return [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: `rgba(${c[0]},${c[1]},${c[2]},0)`, + width: 5 + }) + })]; +} + diff --git a/projects/glrtoc/legendTest.js b/projects/glrtoc/legendTest.js new file mode 100644 index 0000000000000000000000000000000000000000..71ecba4373efc13af700eaad09ceed4e44dd8941 --- /dev/null +++ b/projects/glrtoc/legendTest.js @@ -0,0 +1,129 @@ +/** + * Created by gavorhes on 1/4/2016. + */ +import quickMap from '../../src/olHelpers/quickMap'; +import LayerItsInventory from '../../src/layers/LayerItsInventory'; +import LayerBaseVectorEsri from '../../src/layers/LayerBaseVectorEsri'; +import LayerEsriMapServer from '../../src/layers/LayerEsriMapServer'; +import LayerBaseXyzTile from '../../src/layers/LayerBaseXyzTile'; +import LayerLegend from '../../src/collections/LayerLegend'; +import ItsLayerCollection from '../../src/collections/ItsLayerCollection'; +import mapPopup from '../../src/olHelpers/mapPopup'; + + +(function () { + "use strict"; + let map = quickMap({center: {x: -9907589, y: 5232317}, zoom: 12, minZoom: 3, maxZoom: 19}); + + let itsLayerCollection = new ItsLayerCollection(map); + + let oakRidgeCams = new LayerEsriMapServer( + `http://itsdpro.ornl.gov/arcgis/rest/services/ITSPublic/cameras33/MapServer`, + { + id: 'cameras33', + name: 'Oak Cameras', + visible: true, + minZoom: 7, + zIndex: 20, + addPopup: true + } + ); + + map.addLayer(oakRidgeCams.olLayer); + + glob.cat = (bird) => bird * 2; + + + + + glob.map = map; + + let itsLayer = new LayerItsInventory({itsType: 'CCTV', itsIcon: 'cctv.png', name: 'Camera', visible: false}); + + map.addLayer(itsLayer.olLayer); + + let legend = new LayerLegend( + [ + {groupName: 'its layers', collapse: true, items: itsLayerCollection.layers}, + itsLayer, oakRidgeCams + ], + 'legend-container', {}); + + + + //let legend = new LayerLegend( + // [ + // {groupName: 'its layers', expand: true, items: itsLayerCollection.layers}, + // itsLayer, testEsri, msg, tower, xyzTile, + // {groupName: 'new group', expand: true, items: [rwis, coord, seg, esriMap]} + // ], + // 'legend-container', {}); + + //let legend = new LayerLegend( + // [ + // itsLayerCollection.layers[1] + // ], + // 'legend-container', {}); + + map.getView().setZoom(13); + + return; + + let testEsri = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/3', + {name: 'test esri', useEsriStyle: true, visible: false} + ); + map.addLayer(testEsri.olLayer); + + let msg = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/8', + {name: 'message', useEsriStyle: true, visible: false} + ); + map.addLayer(msg.olLayer); + + let tower = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/0', + {name: 'tower', useEsriStyle: true, visible: false} + ); + map.addLayer(tower.olLayer); + + + let rwis = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/1', + {name: 'rwis', useEsriStyle: true, visible: false} + ); + map.addLayer(rwis.olLayer); + + let coord = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/10', + {name: 'coord', useEsriStyle: true, minZoom: 6, visible: false, collapseLegend: true} + ); + map.addLayer(coord.olLayer); + + //let coord2 = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/11', + // {name: 'coord2', useEsriStyle: true} + //); + //map.addLayer(coord.olLayer); + + let seg = new LayerBaseVectorEsri('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer/9', + {name: 'seg', useEsriStyle: true, visible: false} + ); + map.addLayer(seg.olLayer); + + let esriMap = new LayerEsriMapServer('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/LegendTest/MapServer', { + name: 'esri map', + legendCollapse: true, + legendCheckbox: false, + visible: false + }); + + map.addLayer(esriMap.olLayer); + + let xyzTile = new LayerBaseXyzTile('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/NPMRDS/npmrds_tile/MapServer/tile/{z}/{y}/{x}', + {minZoom: 4, maxZoom: 11, name: "NPMRDS", useEsriStyle: true, collapseLegend: true}); + + //let esriMapServer = new LayerEsriMapServer('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/NPMRDS/npmrds_dynamic/MapServer', + // {minZoom: 12, maxZoom: 18}); + + map.addLayer(xyzTile.olLayer); + //map.addLayer(esriMapServer.olLayer); + + glob.itsCollection = itsLayerCollection; + + +})(); diff --git a/projects/glrtoc/main.js b/projects/glrtoc/main.js new file mode 100644 index 0000000000000000000000000000000000000000..2613e08113cbadf982ee28c1ffad45dc0e544c62 --- /dev/null +++ b/projects/glrtoc/main.js @@ -0,0 +1,319 @@ +/** + * Created by gavorhes on 12/2/2015. + */ + +// <editor-fold desc="imports"> + +import quickMap from '../../src/olHelpers/quickMap'; +import LayerBase from '../../src/layers/LayerBase'; +import LayerBaseVectorGeoJson from '../../src/layers/LayerBaseVectorGeoJson'; +import LayerBaseVectorEsri from '../../src/layers/LayerBaseVectorEsri'; +import LayerRealEarthTile from '../../src/layers/LayerRealEarthTile'; +import LayerRealEarthVector from '../../src/layers/LayerRealEarthVector'; +import LayerEsriMapServer from '../../src/layers/LayerEsriMapServer'; +import * as layerStyles from './layerStyles'; +import * as layerPopups from './layerPopups'; +import mapPopup from '../../src/olHelpers/mapPopup'; +import mapMove from '../../src/olHelpers/mapMove'; +import * as dteConvert from '../../src/util/dateConvert'; +import * as colors from '../../src/util/colors'; +import appConfig from './appConfig'; +import * as uiSetup from './mainUi'; +import LayerLegend from '../../src/collections/LayerLegend'; +// </editor-fold> + +(function () { + "use strict"; + uiSetup.uiInit(); + + let legendItemsStatic = []; + let legendItemsAnimated = []; + let oakRidgeGroup = {groupName: 'Oak Ridge ITS', collapse: false, addCheck: true, items: []}; + let realEarthGroup = {groupName: 'Real Earth', collapse: false, items: []}; + let workZoneEventGroup = {groupName: 'Work Zones / Events', collapse: false, items: []}; + legendItemsStatic.push(oakRidgeGroup); + legendItemsStatic.push(realEarthGroup); + legendItemsStatic.push(workZoneEventGroup); + + function animationLoadCallback() { + appConfig.animationLayers.push(this); + } + + let map = quickMap({center: {x: -85.413, y: 43.29320}, zoom: 6, minZoom: 3, maxZoom: 19}); + appConfig.map = map; + + // <editor-fold desc="Coordination Layer"> + let coordinationLayer = new LayerBaseVectorEsri( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/GlrtocCoordination/MapServer/0', + { + id: appConfig.coordinationLayerId, + visible: true, + autoLoad: true, + name: 'Coordination', + useEsriStyle: true + } + ); + + map.addLayer(coordinationLayer.olLayer); + mapPopup.addVectorPopup(coordinationLayer, layerPopups.coordination); + appConfig.coordinationLayer = coordinationLayer; + + + //appConfig.addLayer(coordinationLayer); + // </editor-fold> + + // <editor-fold desc="Oak Ridge Layers "> + let oakRidgeLayers = [ + ['Cameras', 'cameras33'], + ['HAR', 'HAR33'], + ['DMS', 'MessageSigns33'], + //['State Summary', 'statesummary'], + ['Traffic Control', 'TrafficControl33'], + ['Traffic Detection', 'TrafficDetection33'], + ['Weather', 'Weather33'] + ]; + + + for (let i = 0; i < oakRidgeLayers.length; i++) { + let oakRidgeLayer = new LayerEsriMapServer( + `http://itsdpro.ornl.gov/arcgis/rest/services/ITSPublic/${oakRidgeLayers[i][1]}/MapServer`, + { + id: oakRidgeLayers[i][1], + name: oakRidgeLayers[i][0], + visible: false, + minZoom: 7, + zIndex: 20, + addPopup: true + } + ); + oakRidgeGroup.items.push(oakRidgeLayer); + map.addLayer(oakRidgeLayer.olLayer); + appConfig.addOperationsLayerStatic(oakRidgeLayer); + } + // </editor-fold> + + // <editor-fold desc="WRS Segments"> + + let wrsConfigVector = { + products: 'ROADS', + style: layerStyles.wrsStyle, + animate: false, + id: 'wrs-segments-vector-static', + name: 'Winter Roads', + minZoom: 5, + maxZoom: 13, + zIndex: 3 + }; + + let wrsSegmentLayerVectorStatic = new LayerRealEarthVector(wrsConfigVector); + map.addLayer(wrsSegmentLayerVectorStatic.olLayer); + mapPopup.addVectorPopup(wrsSegmentLayerVectorStatic, layerPopups.wrs); + appConfig.addOperationsLayerStatic(wrsSegmentLayerVectorStatic); + //realEarthGroup.items.push(wrsSegmentLayerVectorStatic); + + wrsConfigVector.animate = true; + wrsConfigVector.id = 'wrs-segments-vector-animate'; + wrsConfigVector.loadCallback = animationLoadCallback; + + let wrsSegmentLayerVectorAnimate = new LayerRealEarthVector(wrsConfigVector); + map.addLayer(wrsSegmentLayerVectorAnimate.olLayer); + mapPopup.addVectorPopup(wrsSegmentLayerVectorAnimate, layerPopups.wrs); + appConfig.addOperationsLayerAnimate(wrsSegmentLayerVectorAnimate); + + let wrsConfigTile = { + products: 'ROADS', + id: 'roads-tile-static', + opacity: 0.6, + animate: false, + name: 'Winter Roads', + zIndex: 10 + }; + + let wrsSegmentLayerTileStatic = new LayerRealEarthTile(wrsConfigTile); + map.addLayer(wrsSegmentLayerTileStatic.olLayer); + appConfig.addOperationsLayerStatic(wrsSegmentLayerTileStatic); + realEarthGroup.items.push(wrsSegmentLayerTileStatic); + + wrsConfigTile.animate = true; + wrsConfigTile.id = 'roads-tile-animate'; + wrsConfigTile.loadCallback = animationLoadCallback; + + let wrsSegmentLayerTileAnimate = new LayerRealEarthTile(wrsConfigTile); + map.addLayer(wrsSegmentLayerTileAnimate.olLayer); + appConfig.addOperationsLayerAnimate(wrsSegmentLayerTileAnimate); + legendItemsAnimated.push(wrsSegmentLayerTileAnimate); + + // </editor-fold> + + // <editor-fold desc="24 hour snow"> + + let snow24Config = { + products: 'SNOWDEPTH24', + id: 'snowdepth24-static', + opacity: 0.5, + animate: false, + name: '24HR Snow', + maxZoom: 9 + }; + + + let snowDepthStatic = new LayerRealEarthTile(snow24Config); + map.addLayer(snowDepthStatic.olLayer); + appConfig.addOperationsLayerStatic(snowDepthStatic); + realEarthGroup.items.push(snowDepthStatic); + + //snow24Config.animate = true; + //snow24Config.id = 'snowdepth24-animate'; + //snow24Config.loadCallback = animationLoadCallback; + // + //let snowDepthAnimate = new LayerRealEarthTile(snow24Config); + //map.addLayer(snowDepthAnimate.olLayer); + //appConfig.addOperationsLayerAnimate(snowDepthAnimate); + //legendItemsAnimated.push(snowDepthAnimate); + + // </editor-fold> + + // <editor-fold desc="nexrhres and precipitation layers"> + let nexrhresConfig = { + products: 'nexrhres', + id: 'nexrhres-static', + opacity: 0.6, + animate: false, + name: 'Hybrid Reflectivity', + maxZoom: 10 + }; + + let nexrhresStatic = new LayerRealEarthTile(nexrhresConfig); + map.addLayer(nexrhresStatic.olLayer); + appConfig.addOperationsLayerStatic(nexrhresStatic); + realEarthGroup.items.push(nexrhresStatic); + + nexrhresConfig.animate = true; + nexrhresConfig.id = 'nexrhres-animate'; + nexrhresConfig.loadCallback = animationLoadCallback; + + let nexrhresAnimate = new LayerRealEarthTile(nexrhresConfig); + map.addLayer(nexrhresAnimate.olLayer); + appConfig.addOperationsLayerAnimate(nexrhresAnimate); + legendItemsAnimated.push(nexrhresAnimate); + + let precipRateConfig = { + products: 'nexrcomp', + id: 'precip-rate-static', + opacity: 0.6, + animate: false, + name: 'Precipitation Rate', + maxZoom: 10 + }; + + let precipRateStatic = new LayerRealEarthTile(precipRateConfig); + map.addLayer(precipRateStatic.olLayer); + appConfig.addOperationsLayerStatic(precipRateStatic); + realEarthGroup.items.push(precipRateStatic); + + precipRateConfig.animate = true; + precipRateConfig.id = 'precip-rate-animate'; + precipRateConfig.loadCallback = animationLoadCallback; + + let precipRateAnimate = new LayerRealEarthTile(precipRateConfig); + map.addLayer(precipRateAnimate.olLayer); + appConfig.addOperationsLayerAnimate(precipRateAnimate); + legendItemsAnimated.push(precipRateAnimate); + + + // </editor-fold> + + // <editor-fold desc="Work Zones and special events"> + let d = new Date(); + d.setSeconds(0); + let endDate = dteConvert.dateToYyyyMmDdHhMmSs(d); + d.setYear(d.getYear() + 1901); + var startDate = dteConvert.dateToYyyyMmDdHhMmSs(d); + + let workZoneSegLayer = new LayerBaseVectorEsri( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/GLRTOC_WZ_SE/MapServer/1', + { + where: `EventStartDate < '${startDate}' AND EventEndDate > '${endDate}' AND Impact IN('High', 'XXX')`, + name: "Work Zone Segments", + style: layerStyles.workZoneAndEventStyle, + id: 'work-zone-segments', + minZoom: 5, + maxZoom: 13 + } + ); + + map.addLayer(workZoneSegLayer.olLayer); + appConfig.addOperationsLayerStatic(workZoneSegLayer); + mapPopup.addVectorPopup(workZoneSegLayer, layerPopups.specialEventWorkZone); + workZoneEventGroup.items.push(workZoneSegLayer); + + let specialEventsLayer = new LayerBaseVectorEsri( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/GLRTOC/GLRTOC_WZ_SE/MapServer/2', + { + where: `EventStartDate < '${startDate}' AND EventEndDate > '${endDate}' AND Impact IN('High', 'XXX')`, + //where: '1=1', + name: "Special Events", + style: layerStyles.workZoneAndEventStyle, + id: 'special-event-points', + minZoom: 5, + maxZoom: 13 + } + ); + + map.addLayer(specialEventsLayer.olLayer); + appConfig.addOperationsLayerStatic(specialEventsLayer); + mapPopup.addVectorPopup(specialEventsLayer, layerPopups.specialEventWorkZone); + workZoneEventGroup.items.push(specialEventsLayer); + + // </editor-fold> + + let legendStatic = new LayerLegend(legendItemsStatic, 'legend-container-static', {}); + let legendAnimate = new LayerLegend(legendItemsAnimated, 'legend-container-animate', {}); + + appConfig.init(); + + uiSetup.uiAfterMap(); +})(); + + +// <editor-fold desc="Promise example"> + +//var promise = new Promise(function (resolve, reject) { +// console.log('doing stuff'); +// +// $.get('http://realearth.ssec.wisc.edu:80/api/products', {products: 'ROADS'}, function (d) { +// //if (d.length == 0) { +// // console.log(`${this._products} layer not available or does not have times`); +// // return; +// //} +// d = d[0]; +// console.log(d); +// resolve("Stuff worked!"); +// +// +// //for (let i = 0; i < d['times'].length; i++) { +// // _this._loadDates.call(_this, d['times'][i]); +// //} +// //console.log(_this._localDates); +// +// //_this._loadAtTimeIndex.call(_this, _this._localDates.length - 1) +// +// }, 'json').fail(function () { +// reject(Error("It broke")); +// }); +// +// +//}); +// +// +//promise.then( +// function (result) { +// console.log(result); // "Stuff worked!" +// }, +// function (err) { +// console.log(err); // Error: "It broke" +// } +//); +// </editor-fold> + + diff --git a/projects/glrtoc/mainUi.js b/projects/glrtoc/mainUi.js new file mode 100644 index 0000000000000000000000000000000000000000..9e4f17c4dc682b1de35401b06d468a78943087c4 --- /dev/null +++ b/projects/glrtoc/mainUi.js @@ -0,0 +1,105 @@ +/** + * Created by gavorhes on 12/7/2015. + */ + +import {} from '../../src/jquery-plugin/mediaControl'; +import {} from '../../src/jquery-plugin/rangeChange'; +import appConfig from './appConfig'; +import $ from '../../src/jquery'; +require('jquery-ui/tabs'); +require('jquery-ui/accordion'); + + +/** + * Set up the UI + */ +export function uiInit() { + "use strict"; + + //$("#operations").accordion('refresh'); + + + let $sidebar = $('#sidebar'); + let $hideSideBar = $('#hide-sidebar'); + let $showSideBar = $('#show-sidebar'); + + let $tabs = $("#tabs"); + + let sidebarWidth = $sidebar.width(); + + //apply tab layout + $tabs.tabs({ + heightStyle: "fill", + activate: function (event, ui) { + appConfig.currentTabId = ui.newPanel[0].id; + } + }); + + //apply accordion + appConfig.$opsAccordion.accordion({ + heightStyle: "fill", + activate: function (event, ui) { + appConfig.currentOperationsPanelId = ui.newPanel[0].id; + } + }); + + $(window).resize(function () { + $tabs.tabs('refresh'); + setTimeout(function () { + appConfig.$opsAccordion.accordion("refresh"); + }, 50); + }); + + $hideSideBar.click(function () { + var mapCenter = appConfig.map.getView().getCenter(); + + appConfig.map.beforeRender(function () { + $sidebar.animate({'margin-left': -1 * sidebarWidth}, 200, + function () { + $hideSideBar.hide(); + $showSideBar.show(); + appConfig.map.updateSize(); + } + ); + }); + appConfig.map.getView().setCenter(mapCenter); + }); + + $showSideBar.click(function () { + var mapCenter = appConfig.map.getView().getCenter(); + + appConfig.map.beforeRender(function () { + $sidebar.animate({'margin-left': 0}, 200, + function () { + $showSideBar.hide(); + $hideSideBar.show(); + appConfig.map.updateSize(); + } + ); + }); + appConfig.map.getView().setCenter(mapCenter); + }); + + let d = new Date(); + let endTime = d.getTime(); + d.setHours(d.getHours() - 4); + let startTime = d.getTime(); + let rangeStep = Math.round((endTime - startTime) / 8); + + appConfig.mediaControl = $('#animation-control').mediaControl(startTime, endTime, endTime, rangeStep, + function (t) { + for (let l of appConfig.animationLayers) { + l.setLayerTime(t); + } + }, + 750, true); +} + + +//http://realearth.ssec.wisc.edu/api/image?products=nexrhres_20160108_180000&x=5&y=5&z=4 + +export function uiAfterMap() { + "use strict"; + + +} \ No newline at end of file diff --git a/projects/itsMap.js b/projects/itsMap.js new file mode 100644 index 0000000000000000000000000000000000000000..d31b6c55c261faf2095522c102093dd723fd5355 --- /dev/null +++ b/projects/itsMap.js @@ -0,0 +1,27 @@ +/** + * Created by gavorhes on 12/18/2015. + */ + +import quickMap from '../src/olHelpers/quickMap'; +import mapMove from '../src/olHelpers/mapMove'; +import mapPopup from '../src/olHelpers/mapPopup'; +import ItsLayerCollection from '../src/collections/ItsLayerCollection'; +import LayerLegend from '../src/collections/LayerLegend'; + +let map = quickMap(); +mapMove.init(map); +mapPopup.init(map); + +let itsLayerCollection = new ItsLayerCollection(map); + +let layerArray = [ + { + groupName: 'ITS Inventory Layers', + collapse: false, + addCheck: true, + items: itsLayerCollection.layers + } +]; + + +let legend = new LayerLegend(layerArray, 'legend-container', {}); diff --git a/projects/npmrds/delay/delay-config.js b/projects/npmrds/delay/delay-config.js new file mode 100644 index 0000000000000000000000000000000000000000..5be9a94e0e24857e670c42b0da45a6a41434b8fc --- /dev/null +++ b/projects/npmrds/delay/delay-config.js @@ -0,0 +1,3 @@ +/** + * Created by gavorhes on 2/9/2016. + */ diff --git a/projects/npmrds/delay/delay-main.js b/projects/npmrds/delay/delay-main.js new file mode 100644 index 0000000000000000000000000000000000000000..b0783f402689ece7127771e36855c344f53ee45b --- /dev/null +++ b/projects/npmrds/delay/delay-main.js @@ -0,0 +1,32 @@ +/** + * Created by gavorhes on 2/9/2016. + */ + +import quickMap from '../../../src/olHelpers/quickMap'; +const angular = require('angular2'); + +let map = quickMap(); + +let app = angular.module('myApp', []); + + +app.controller('myCtrl', function($scope) { + $scope.firstName = "John"; + $scope.lastName = "Doe"; + + $scope.myFunction = function(){ + "use strict"; + console.log((new Date()).getTime()); + }; +}); + + +app.controller('myCtrl2', function($scope) { + //$scope.firstName = "John"; + //$scope.lastName = "Doe"; + // + //$scope.myFunction = function(){ + // "use strict"; + // console.log((new Date()).getTime()); + //} +}); diff --git a/projects/npmrds/heatmap/appConfig.js b/projects/npmrds/heatmap/appConfig.js new file mode 100644 index 0000000000000000000000000000000000000000..32d4fcbdc123a3e2c47d27e67f5e65e998de8310 --- /dev/null +++ b/projects/npmrds/heatmap/appConfig.js @@ -0,0 +1,50 @@ +/** + * Created by gavorhes on 12/23/2015. + */ + +class NpmrdsHeatmapConfig { + constructor() { + + this.map = undefined; + + /** + * + * @type {LayerBaseVectorGeoJson} + */ + this.featureOverlay = undefined; + + /** + * + * @type {LayerBaseVectorGeoJson} + */ + this.lineLayer = undefined; + + + /** + * + * @type {LayerBaseVectorGeoJson} + */ + this.pointLayer = undefined; + + + /** + * + * @type {LayerBaseVectorGeoJson} + */ + this.trackerLayer = undefined; + } + + +} + +///** +// * +// * @type {NpmrdsHeatmapConfig} +// */ +//const npmrdsHeatmapConfig = new NpmrdsHeatmapConfig(); + +/** + * @type {NpmrdsHeatmapConfig} + */ +export default new NpmrdsHeatmapConfig(); + diff --git a/projects/npmrds/heatmap/layerStyles.js b/projects/npmrds/heatmap/layerStyles.js new file mode 100644 index 0000000000000000000000000000000000000000..e16bd69ff74e2f6797d6d2902e73e1c1046eebf9 --- /dev/null +++ b/projects/npmrds/heatmap/layerStyles.js @@ -0,0 +1,43 @@ +/** + * Created by gavorhes on 12/22/2015. + */ +import ol from '../../../src/custom-ol'; + + +export const overlayStyle = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 0, 237, 0.1)' + }), + stroke: new ol.style.Stroke({ + color: 'rgb(255, 0, 237)', + width: 2 + }) +}); + + +export const lineIndicator = new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'red', + width: 7 + }) +}); + + +export const pointIndices = new ol.style.Style({ + image: new ol.style.Circle({ + radius: 4, + fill: new ol.style.Fill({ + color: 'blue' + }) + }) +}); + + +export const trackerPoint = new ol.style.Style({ + image: new ol.style.Circle({ + radius: 8, + fill: new ol.style.Fill({ + color: 'blue' + }) + }) +}); diff --git a/projects/npmrds/heatmap/main-ui.js b/projects/npmrds/heatmap/main-ui.js new file mode 100644 index 0000000000000000000000000000000000000000..7f6a44a225255824550a32012f197d205b285f29 --- /dev/null +++ b/projects/npmrds/heatmap/main-ui.js @@ -0,0 +1,368 @@ +/** + * Created by gavorhes on 12/22/2015. + */ + +import npmrdsHeatmapConfig from './appConfig'; +import {} from '../../../src/jquery-plugin/dayRange'; +import {} from '../../../src/jquery-plugin/rangeChange'; +import * as colors from '../../../src/util/colors'; +import SortedFeatures from '../../../src/olHelpers/SortedFeatures'; +import $ from '../../../src/jquery'; +import ol from '../../../src/custom-ol'; + + +let $btnCancelArea = $('#btn-cancel-area'); +let $btnSelectArea = $('#btn-select-area'); +let $divSelectArea = $('#div-select-area'); +let $ulHwyDirs = $('#ul-hwy-dirs'); +let $btnSelectHwy = $('#btn-select-hwy'); +//let $btnSelectHwyBack = $('#btn-select-hwy-back'); +let $divHighwaySelection = $('#div-highway-selection'); +let $divRight = $('#right'); +let $divLeft = $('#left'); +let $ckmapTrack = $('#chk-map-track'); +let $canvasToolTipSpan = $('#canvas-tooltip-span'); +let $canv = $('#heatmap-canvas'); +/** + * + * @type {*|jQuery|HTMLElement} + */ +let $canvContainer = $('#canvas-container'); +let $dateUl = $('#date-ul'); +let $heatMapVerticalBar = $('#heat-map-vertical-bar'); +let $selectedTmcs = $('#selected-tmcs'); + +let sldrHeatMapId = 'heat-map-slider'; +let $sldrHeatMap = $('#' + sldrHeatMapId); + + +let heatMapReady = false; + +/** + * @type {SortedFeatures} + */ +let sortedFeatures; + +/** + * @type {DayRange} + */ +let dayRange; + +function _leadingPad(num) { + let out = num.toFixed(); + if (out.length == 1) { + out = '0' + out; + } + + return out; +} + +function _formatDate(d) { + return `${_leadingPad(d.getMonth() + 1)}/${_leadingPad(d.getDate())}/${d.getYear() + 1900} ` + + `${_leadingPad(d.getHours())}:${_leadingPad(d.getMinutes())}:${_leadingPad(d.getSeconds())}`; +} + + + +function clearCanvas() { + $dateUl.html(''); + $canv.off('mousemove'); + let canv = $canv[0]; + let ctx = canv.getContext("2d"); + ctx.clearRect(0, 0, canv.width, canv.height); + + $canv.attr('width', $('#heat-map-slider').width()); + $canv.attr('height', 100); + $heatMapVerticalBar.height(0); +} + + +export function startUi() { + "use strict"; + dayRange = $('#div-date-range').dayRange(10); +} + +export function drawSetup() { + "use strict"; + let draw = new ol.interaction.Draw({ + source: npmrdsHeatmapConfig.featureOverlay.source, + type: 'Polygon' + }); + + draw.on('drawend', function (evt) { + //$divSelectArea.hide(); + $btnSelectArea.prop('disabled', false); + let geom = evt.feature.getGeometry(); + let geomClone = geom.clone(); + + geomClone.transform('EPSG:3857', 'EPSG:4326'); + + setTimeout(function () { + npmrdsHeatmapConfig.map.removeInteraction(draw); + }, 100); + $btnCancelArea.hide(); + + $.get('npmrds/gethighways', {polygon: JSON.stringify(geomClone.getCoordinates())}, + function (d) { + $ulHwyDirs.html(d); + $divHighwaySelection.show(); + + $('input[name=hwydirs]').change(function () { + $btnSelectHwy.prop('disabled', false); + }); + }, 'text'); + }); + + $btnCancelArea.click(function () { + npmrdsHeatmapConfig.map.removeInteraction(draw); + $btnSelectArea.prop('disabled', false); + $btnCancelArea.hide(); + }); + + $btnSelectArea.click(function () { + npmrdsHeatmapConfig.featureOverlay.source.clear(); + npmrdsHeatmapConfig.map.addInteraction(draw); + $btnSelectArea.prop('disabled', true); + $btnCancelArea.show(); + $ulHwyDirs.html(''); + $divHighwaySelection.hide(); + $btnSelectHwy.prop('disabled', true); + }); +} + + +export function endUi() { + "use strict"; + + $divSelectArea.show(); + $btnSelectArea.prop('disabled', false); + $btnCancelArea.hide(); + $divHighwaySelection.hide(); + + $btnSelectHwy.click(function () { + let selectedHwy = $('input[name=hwydirs]:checked:first').val(); + $('#sel-hwy').html(selectedHwy); + $.get('npmrds/getroute', + { + hwyDir: selectedHwy + }, function (d) { + npmrdsHeatmapConfig.lineLayer.clear(); + npmrdsHeatmapConfig.lineLayer.addFeatures(d['line']); + + npmrdsHeatmapConfig.pointLayer.clear(); + npmrdsHeatmapConfig.pointLayer.addFeatures(d['points']); + + sortedFeatures = new SortedFeatures(npmrdsHeatmapConfig.pointLayer.source.getFeatures(), 'distReal'); + + npmrdsHeatmapConfig.trackerLayer.clear(); + npmrdsHeatmapConfig.trackerLayer.source.addFeature(sortedFeatures.sortedFeatures[0]); + + + $divLeft.hide(); + $divRight.show(); + npmrdsHeatmapConfig.map.updateSize(); + + let mapView = npmrdsHeatmapConfig.map.getView(); + + let panAnimation = ol.animation.pan({ + duration: 500, + source: mapView.getCenter() + }); + npmrdsHeatmapConfig.map.beforeRender(panAnimation); + + mapView.fit( + npmrdsHeatmapConfig.featureOverlay.source.getFeatures()[0].getGeometry().getExtent(), + npmrdsHeatmapConfig.map.getSize() + ); + + mapView.setZoom(mapView.getZoom() - 1); + + $('#vehicle-all').prop('checked', true); + + npmrdsHeatmapConfig.featureOverlay.visible = false; + npmrdsHeatmapConfig.lineLayer.visible = true; + npmrdsHeatmapConfig.pointLayer.visible = true; + npmrdsHeatmapConfig.trackerLayer.visible = true; + + $sldrHeatMap.prop('max', d['totalDistance']); + $sldrHeatMap.val(0); + $heatMapVerticalBar.css('left', '22px'); + $selectedTmcs.val(JSON.stringify(d['tmcs'])); + + //console.log(d); + }, 'json').fail(function () { + alert("something went wrong, try another area selection"); + }); + }); +} + + +export function heatMapUi() { + "use strict"; + + $('#heat-map-back').click(function () { + $divLeft.show(); + $divRight.hide(); + npmrdsHeatmapConfig.map.updateSize(); + npmrdsHeatmapConfig.featureOverlay.visible = true; + npmrdsHeatmapConfig.lineLayer.visible = false; + npmrdsHeatmapConfig.pointLayer.visible = false; + npmrdsHeatmapConfig.trackerLayer.visible = false; + + clearCanvas(); + }); + + $canv.mouseenter(function () { + if (heatMapReady) { + $canvasToolTipSpan.css('display', 'block'); + } + }); + + $canv.mouseleave(function () { + $canvasToolTipSpan.css('display', 'none'); + $canvasToolTipSpan.html(''); + }); + + //add the slider change interaction + $('#' + sldrHeatMapId).rangeChange(function(newVal, percent, evt){ + + let canvWidth = parseFloat($canv.width()); + + $heatMapVerticalBar.css('left', (canvWidth * percent + 22).toFixed() + 'px'); + + let selectedFeature = sortedFeatures.getFeature(newVal); + + npmrdsHeatmapConfig.trackerLayer.clear(); + npmrdsHeatmapConfig.trackerLayer.source.addFeature(selectedFeature); + + if ($ckmapTrack.prop('checked')) { + let panAnimation = ol.animation.pan({ + duration: 500, + source: npmrdsHeatmapConfig.map.getView().getCenter() + }); + npmrdsHeatmapConfig.map.beforeRender(panAnimation); + npmrdsHeatmapConfig.map.getView().setCenter(selectedFeature.getGeometry().getCoordinates()); + } + }, 25); + + + $('#heat-map-confirm').click(function () { + clearCanvas(); + let canv = $canv[0]; + let ctx = canv.getContext("2d"); + let $progressDiv = $('#progress-indicator-div'); + $dateUl.html(''); + + $progressDiv.show(); + + $.get('npmrds/getheatmap', + { + vehicleType: $('input[name=vehicle-type]:checked:first').val(), + startDate: _formatDate(dayRange.startDate), + endDate: _formatDate(dayRange.endDate), + tmcs: $selectedTmcs.val() + }, function (d) { + if (d['error']) { + alert(d['error']); + + return; + } + + let canvasWidth = parseInt($canv.attr('width')); + let colorGradient = colors.makeBlueGreenRedGradient(d['minSpeedVsFree'], d['maxSpeedVsFree'], true); + let colorGradientStdDev = colors.makeBlueGreenRedGradientZScore(d['medianSpeedVsFree'], d['stdDevSpeedVsFree'], true); + + let recordLength = d['tmcResult'][0].values.length; + $canv.attr('height', (recordLength * 2).toFixed()); + $heatMapVerticalBar.height(recordLength * 2); + + let columnPosition = 0; + let tmcEndPositionArray = []; + + for (let i = 0; i < d['tmcResult'].length; i++) { + let tmc = d['tmcResult'][i]; + let rectangleWidth = canvasWidth * tmc['distPercent'] / 100; + let valLength = tmc['values'].length; + + for (let j = 0; j < valLength; j++) { + let speedVFreeSpeed = (tmc['values'][j] == null ? null : tmc['values'][j] / tmc['freeFlowSpeed']); + let speedVFreeZScore = (speedVFreeSpeed - d['medianSpeedVsFree']) / d['stdDevSpeedVsFree']; + //console.log(colorGradientStdDev(speedVFreeSpeed)); + //let z_score = + //let z_score = + + ctx.fillStyle = colorGradientStdDev(speedVFreeSpeed); + ctx.fillRect(columnPosition, j * 2, rectangleWidth, 2); + } + + columnPosition += rectangleWidth; + tmcEndPositionArray.push([tmc['tmc'], columnPosition]); + } + + for (let i = 0; i < d['dateList'].length; i++) { + $dateUl.append('<li><div>' + d['dateList'][i] + '</div></ul>'); + } + + // set the date li height + //$('#date-ul li').css('height', (2 + (parseInt($canv.attr('height')) / d['dateList'].length) - d['dateList'].length).toFixed()); + + let tmcResultDict = {}; + for (let i = 0; i < d['tmcResult'].length; i++) { + tmcResultDict[d['tmcResult'][i]['tmc']] = d['tmcResult'][i]; + } + + $canv.mousemove(function (evt) { + + // coordinates relative the canvas + let offsetX = evt.offsetX; + let offsetY = evt.offsetY; + + // coordinates relative the window + let clientX = evt.clientX; + let clientY = evt.clientY; + + // get the tmc + let tmcId = null; + for (let i = 0; i < tmcEndPositionArray.length; i++) { + if (offsetX < tmcEndPositionArray[i][1]) { + tmcId = tmcEndPositionArray[i][0]; + break; + } + } + + if (tmcId == null) { + tmcId = tmcEndPositionArray[tmcEndPositionArray.length - 1][0]; + } + + // since each retangle in the heatmap is 2px high, get the index by divding by 2, round down + let rowIndex = Math.floor(offsetY / 2); + + // make a date equal to the query start date + let dte = new Date(d['dateList'][0]); + // add minutes as 5X the row index + dte.setMinutes(dte.getMinutes() + rowIndex * 5); + + let tmcObj = tmcResultDict[tmcId]; + + //set the html + $canvasToolTipSpan.html(`TMC: ${tmcId}<br>${dte.toLocaleDateString()} ${dte.toLocaleTimeString()}<br>` + + `Speed: ${(tmcObj['values'][rowIndex] == null ? 'null' : tmcObj['values'][rowIndex].toFixed(1))}, Free: ${tmcObj['freeFlowSpeed'].toFixed(1)}` + ); + + //set the position + let canvasToolipSpan = $canvasToolTipSpan[0]; + canvasToolipSpan.style.left = (clientX - 150).toFixed() + 'px'; + canvasToolipSpan.style.top = (clientY - 85).toFixed() + 'px'; + + }); + //console.log(d); + + $canvContainer.scrollTop(0); + heatMapReady = true; + }, 'json').fail(function(){ + alert('Something went wrong with the request'); + }).always(function(){ + $progressDiv.hide(); + }); + }); +} diff --git a/projects/npmrds/heatmap/main.js b/projects/npmrds/heatmap/main.js new file mode 100644 index 0000000000000000000000000000000000000000..23973777d705e6d5e2d8600450ae3aeb257d490e --- /dev/null +++ b/projects/npmrds/heatmap/main.js @@ -0,0 +1,47 @@ +/** + * Created by gavorhes on 12/22/2015. + */ + +import npmrdsHeatmapConfig from './appConfig'; +import quickMap from '../../../src/olHelpers/quickMap'; +import LayerBaseXyzTile from '../../../src/layers/LayerBaseXyzTile'; +import LayerEsriMapServer from '../../../src/layers/LayerEsriMapServer'; +import LayerBaseVectorGeoJson from '../../../src/layers/LayerBaseVectorGeoJson'; +import * as layerStyles from './layerStyles'; +import * as uiSetup from './main-ui'; + +//glob.appConfig = npmrdsHeatmapConfig; + +(function(){ + "use strict"; + uiSetup.startUi(); + let map = quickMap({center: {x: -10012438, y: 5548095}, zoom: 8, minZoom: 5}); + + npmrdsHeatmapConfig.map = map; + + let xyzTile = new LayerBaseXyzTile('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/NPMRDS/npmrds_tile/MapServer/tile/{z}/{y}/{x}', + {minZoom: 4, maxZoom: 11}); + + let esriMapServer = new LayerEsriMapServer('http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/NPMRDS/npmrds_dynamic/MapServer', + {minZoom: 12, maxZoom: 18}); + + map.addLayer(xyzTile.olLayer); + map.addLayer(esriMapServer.olLayer); + + let transform = {dataProjection: 'EPSG:3857', featureProjection: 'EPSG:3857'}; + + npmrdsHeatmapConfig.featureOverlay = new LayerBaseVectorGeoJson('', {style: layerStyles.overlayStyle, transform: transform}); + npmrdsHeatmapConfig.lineLayer = new LayerBaseVectorGeoJson('', {style: layerStyles.lineIndicator, transform: transform}); + npmrdsHeatmapConfig.pointLayer = new LayerBaseVectorGeoJson('', {style: layerStyles.pointIndices, transform: transform}); + npmrdsHeatmapConfig.trackerLayer = new LayerBaseVectorGeoJson('', {style: layerStyles.trackerPoint, transform: transform}); + + map.addLayer(npmrdsHeatmapConfig.featureOverlay.olLayer); + map.addLayer(npmrdsHeatmapConfig.lineLayer.olLayer); + //map.addLayer(npmrdsHeatmapConfig.pointLayer.olLayer); + map.addLayer(npmrdsHeatmapConfig.trackerLayer.olLayer); + + uiSetup.drawSetup(); + uiSetup.heatMapUi(); + uiSetup.endUi(); +})(); + diff --git a/projects/tsmo/TipConfig.js b/projects/tsmo/TipConfig.js new file mode 100644 index 0000000000000000000000000000000000000000..705a404b87a43624e54becc69c7311d596699029 --- /dev/null +++ b/projects/tsmo/TipConfig.js @@ -0,0 +1,149 @@ +/** + * Created by gavorhes on 12/14/2015. + */ + +/** + * Tip config object + */ +class TipConfig { + constructor() { + + /** + * + * @type {Sliders} + */ + this.sliders = undefined; + + /** + * + * @type {Map} + */ + this.map = null; + + this.$loadingGif = null; + this.$regionSelector = undefined; + + /** + * + * @type {TipSegmentLayer} + */ + this.tipSegmentLayer = undefined; + + + /** + * + * @type {LayerBase|*} + */ + this.metamanagerSegments = undefined; + this.tipSegmentLayerMinZoom = 10; + + /** + * its layer collection + * @type {ItsLayerCollection} + */ + this.itsLayerCollection = undefined; + + /** + * param list to set up the sliders, initial weight and drop down selection added later + */ + this._sliderParamArray = [ + ['AADT', [['aadtyr_1', '1']]], + ['AADT Future', [['aadtyr_5', '5'], ['aadtyr_10', '10'], ['aadtyr_15', '15'], ['aadtyr_20', '20']]], + ['Growth', [['growth_5', '5'], ['growth_10', '10'], ['growth_15', '15'], ['growth_20', '20']]], + ['Truck', [['trkdyr_1', '1'], ['trkdyr_20', '20']]], + ['LOS', [['losyr_1', '1']]], + ['LOS Future', [['losyr_5', '5'], ['losyr_10', '10'], ['losyr_15', '15'], ['losyr_20', '20']]], + ['Crash Rate', [['crash_rate', '1']]], + ['Severity', [['crash_severity', '1']]], + ['Weather', [['weather', '1']]], + ['Event', [['event', '1']]] + ]; + + /** + * Presets list, order of the parameters is important, must match that of the slider param list + */ + this._presetArray = + [ + ['Default TIP', [ + [10.0, 'aadtyr_1'], + [7.0, 'aadtyr_20'], + [7.0, 'growth_20'], + [4.0, 'trkdyr_1'], + [12.0, 'losyr_1'], + [12.0, 'losyr_20'], + [15.0, 'crash_rate'], + [13.0, 'crash_severity'], + [9.0, 'weather'], + [11.0, 'event']] + ], + ['Safety', [ + [20.0, 'aadtyr_1'], + [0.0, 'aadtyr_20'], + [0.0, 'growth_20'], + [0.0, 'trkdyr_1'], + [0.0, 'losyr_1'], + [0.0, 'losyr_20'], + [40.0, 'crash_rate'], + [40.0, 'crash_severity'], + [0.0, 'weather'], + [0.0, 'event']] + ], + ['Mobility Present', [ + [25.0, 'aadtyr_1'], + [25.0, 'aadtyr_5'], + [0.0, 'growth_20'], + [25.0, 'trkdyr_1'], + [25.0, 'losyr_1'], + [0.0, 'losyr_20'], + [0.0, 'crash_rate'], + [0.0, 'crash_severity'], + [0.0, 'weather'], + [0.0, 'event']] + ], + ['Mobility Future', [ + [0.0, 'aadtyr_1'], + [25.0, 'aadtyr_20'], + [25.0, 'growth_20'], + [25.0, 'trkdyr_20'], + [0.0, 'losyr_1'], + [25.0, 'losyr_20'], + [0.0, 'crash_rate'], + [0.0, 'crash_severity'], + [0.0, 'weather'], + [0.0, 'event']] + ], + ['Service', [ + [30.0, 'aadtyr_1'], + [0.0, 'aadtyr_20'], + [10.0, 'growth_20'], + [0.0, 'trkdyr_1'], + [30.0, 'losyr_1'], + [30.0, 'losyr_20'], + [0.0, 'crash_rate'], + [0.0, 'crash_severity'], + [0.0, 'weather'], + [0.0, 'event']] + ], + ['Freight Performance', [ + [20.0, 'aadtyr_1'], + [0.0, 'aadtyr_20'], + [0.0, 'growth_20'], + [60.0, 'trkdyr_1'], + [20.0, 'losyr_1'], + [0.0, 'losyr_20'], + [0.0, 'crash_rate'], + [0.0, 'crash_severity'], + [0.0, 'weather'], + [0.0, 'event']] + ] + ]; + + for (var i = 0; i < this._sliderParamArray.length; i++) { + this._sliderParamArray[i].push(this._presetArray[0][1][i][0]); + this._sliderParamArray[i].push(this._presetArray[0][1][i][1]); + } + + } +} + +export default new TipConfig(); diff --git a/projects/tsmo/TipSegmentLayer.js b/projects/tsmo/TipSegmentLayer.js new file mode 100644 index 0000000000000000000000000000000000000000..60f299b904280e56583071187d14a8d0f806bd36 --- /dev/null +++ b/projects/tsmo/TipSegmentLayer.js @@ -0,0 +1,191 @@ +/** + * Created by gavorhes on 12/10/2015. + */ + +import LayerBaseVectorGeoJson from '../../src/layers/LayerBaseVectorGeoJson'; +import mapMove from '../../src/olHelpers/mapMove'; +import mapPopup from '../../src/olHelpers/mapPopup'; +import tipConfig from './TipConfig' +import * as tipLayerStyles from './tipStyleFunction'; +const $ = require('jquery'); + +/** + * Tip Segment layer with a bunch of configuration applied, extends base GeoJSON + */ +class TipSegmentLayer extends LayerBaseVectorGeoJson { + + /** + * ITS device layer, types available at http://transportal.cee.wisc.edu/its/inventory/ + * @param {Sliders} sliders + * @param {object} options + * @param {boolean} [options.visible=true] + * @param {boolean} [options.onDemand=true] + * @param {number} [options.onDemandDelay=300] delay before the map move callback should be called + * @param [options.$loadingGif=undefined] jquery reference to loading gif + * @param [options.$regionSelector=undefined] jquery reference to region selector + * + * @param {object} [options.selectionStyle={}] the selection style configuration + * @param {string} [options.selectionStyle.color=rgba(255,170,0,0.5)] the selection color + * @param {number} [options.selectionStyle.width=10] the selection width for linear features + * @param {object} [options.selectionStyle.olStyle=undefined] an openlayers style object + * @param {propertiesZoomStyle} [options.selectionStyle.olStyleFunction=undefined] modified OL style function + */ + constructor(sliders, options) { + options['name'] = "TIP Segments"; + options.onDemand = true; + options.style = tipLayerStyles.tipStyle; + options['minZoom'] = tipConfig.tipSegmentLayerMinZoom; + options['transform'] = {}; + options.transform.dataProjection = 'EPSG:3857'; + options.transform.featureProjection = 'EPSG:3857'; + options['id'] = 'tip-segments'; + super('tip/gettipfeatures?callback=?', options); + this._$regionSelector = options.$regionSelector || undefined; + + + this._$loadingGif = options.$loadingGif; + + this.legendContent += '<ul><li><hr class="cell-min"></li><li><hr class="cell-very-low"></li>' + + '<li><hr class="cell-low"></li><li><hr class="cell-mid"></li><li><hr class="cell-high"></li>' + + '<li><hr class="cell-very-high"></li><li><hr class="cell-max">' + + '</li></ul>'; + + this.legendContent += '<ul>'; + this.legendContent += '<li style="height: 15px;">low</li>'; + this.legendContent += '<li style="height: 25px; margin-top: 4px;">medium</li>'; + this.legendContent += '<li style="height: 15px; margin-top: 5px;">high</li>'; + this.legendContent += '</ul>'; + + this.legendContent += '<span style="margin: 12px 0 0 52px; display: block">Relative Need</span>'; + + this._geometry_cache = []; + + this.sliders = sliders; + tipConfig.tipSegmentLayer = this; + + let _this = this; + + mapPopup.addVectorPopup(this, function (props) { + + let parms = { + pdpId: props['p'], + paramWeights: JSON.stringify(_this.sliders.getParams()) + }; + + return '<iframe style="margin-top:5px;" ' + + `src="tip/getsegprops?${$.param(parms)}" ` + + `height="250" width="350"></iframe>`; + }, options.selectionStyle); + } + + /** + * override base method to include show or hide loading indicator + * @param {number} zoom + * @param {string} [evtType=undefined] undefined for initial load, otherwise one of 'change:center', 'change:resolution' + * @returns {boolean} + */ + mapMoveBefore(zoom, evtType) { + let returnVal = super.mapMoveBefore(zoom, evtType); + + if (this._$loadingGif) { + if (returnVal) { + this._$loadingGif.fadeIn(); + } else { + this._$loadingGif.fadeOut(); + } + } + return returnVal; + } + + /** + * callback to generate the parameters passed in the get request + * @param {object} extent + * @param {number} extent.minX + * @param {number} extent.minY + * @param {number} extent.maxX + * @param {number} extent.maxY + * @param {number} zoomLevel + */ + mapMoveMakeGetParams(extent, zoomLevel) { + super.mapMoveMakeGetParams(extent, zoomLevel); + $.extend(this.mapMoveParams, extent); + this.mapMoveParams['param_weights'] = JSON.stringify(this.sliders.getParams()); + if (this._$regionSelector){ + this.mapMoveParams['region'] = this._$regionSelector.val(); + } + } + + + /** + * callback function on map move + * @param d the json response + */ + mapMoveCallback(d) { + if (d['geojson'].features.length > 0) { + this._geometry_cache = this._geometry_cache.concat(d['geojson'].features); + this._geometry_cache.sort(function (a, b) { + return (a.properties['p'] - b.properties['p']); + }); + } + + let passFeatures = []; + + for (let s of d['scores']) { + + let feat = this._set_pdp_score(s['p'], s['z']); + if (feat) { + passFeatures.push(feat); + } + } + + d['geojson'].features = passFeatures; + super.mapMoveCallback(d['geojson']); + if (this._$loadingGif) { + this._$loadingGif.fadeOut(); + } + } + + /** + * set the score for the feature + * @param {number} pdp pdp_id + * @param {number} score to assign + * @param {object} [in_array=this._geometry_cache] + * @returns {*} the feature with the score assigned + * @private + */ + _set_pdp_score(pdp, score, in_array) { + if (typeof in_array == 'undefined') { + in_array = this._geometry_cache; + } + + if (in_array.length == 0) { + return undefined; + } + + if (in_array.length == 1) { + let feat = in_array[0]; + if (feat.properties['p'] == pdp) { + feat.properties['z'] = score; + return feat; + } else { + return undefined; + } + } + + let midPoint = Math.floor(in_array.length / 2); + + let midFeature = in_array[midPoint]; + if (midFeature.properties['p'] == pdp) { + midFeature.properties['z'] = score; + return midFeature; + } else if (pdp < midFeature.properties['p']) { + return this._set_pdp_score(pdp, score, in_array.slice(0, midPoint)); + } else { + return this._set_pdp_score(pdp, score, in_array.slice(midPoint + 1)); + } + } + +} + + +export default TipSegmentLayer; diff --git a/projects/tsmo/legend-test.js b/projects/tsmo/legend-test.js new file mode 100644 index 0000000000000000000000000000000000000000..361da6767f3f3946e51754dfb6f7b3ee68672b55 --- /dev/null +++ b/projects/tsmo/legend-test.js @@ -0,0 +1,84 @@ +/** + * Created by gavorhes on 12/18/2015. + */ +import quickMap from '../../src/olHelpers/quickMap'; +import mapMove from '../../src/olHelpers/mapMove'; +import mapPopup from '../../src/olHelpers/mapPopup'; +import ItsLayerCollection from '../../src/collections/ItsLayerCollection'; +import LayerLegend from '../../src/collections/LayerLegend'; + +let map = quickMap(); + +mapMove.init(map); +mapPopup.init(map); + +let itsLayerCollection = new ItsLayerCollection(map); + +let layerArray = [ + { + groupName: 'ITS Inventory Layers', + collapse: false, + addCheck: false, + items: itsLayerCollection.layers + } +]; + +let legend = new LayerLegend(layerArray, 'legend-container', {}); + +// +//let layerArry = itsLayerCollection.layers.slice(0, 3); +// +//layerArry.push( +// { +// groupName: 'Group 1', +// collapse: false, +// items: itsLayerCollection.layers.slice(3, 6) +// } +//); +// +//layerArry.push(itsLayerCollection.layers[6]); +// +//let collection2 = itsLayerCollection.layers.slice(7, 9); +//collection2.push({ +// +// groupName: 'Group 3', +// collapse: false, +// items: itsLayerCollection.layers.slice(10, 12) +// +//}); +// +//layerArry.push( +// { +// groupName: 'Group 2', +// collapse: true, +// items: collection2 +// } +//); +// +//let layerArray = [ +// itsLayerCollection.layers[0], +// itsLayerCollection.layers[1], +// { +// +// groupName: 'Group 1', +// collapse: false, +// items: [itsLayerCollection.layers[2], itsLayerCollection.layers[3]] +// }, +// { +// groupName: 'Group 2', +// collapse: true, +// addCheck: false, +// items: [ +// itsLayerCollection.layers[4], +// itsLayerCollection.layers[5], +// { +// groupName: 'Group 3', +// collapse: false, +// items: [itsLayerCollection.layers[6], itsLayerCollection.layers[7]] +// } +// ] +// } +//]; + + + diff --git a/projects/tsmo/main-report.js b/projects/tsmo/main-report.js new file mode 100644 index 0000000000000000000000000000000000000000..6b8d9489a6d0f66010cca739f8aa83cf6c6924c9 --- /dev/null +++ b/projects/tsmo/main-report.js @@ -0,0 +1,198 @@ +/** + * Created by gavorhes on 12/22/2015. + */ + +import quickMap from '../../src/olHelpers/quickMap'; +import LayerBaseVectorGeoJson from '../../src/layers/LayerBaseVectorGeoJson'; +import mapPopup from '../../src/olHelpers/mapPopup'; +import * as tipLayerStyles from './tipStyleFunction'; +import LayerEsriMapServer from '../../src/layers/LayerEsriMapServer'; +import ItsLayerCollection from '../../src/collections/ItsLayerCollection'; +import LayerLegend from '../../src/collections/LayerLegend'; +import {} from '../../lib/jquery.floatThead'; +let $ = require('jquery'); + +let suppressLowScores = true; + +function tipStyleReport(feature, resolution) { + "use strict"; + + let seg_score = feature.getProperties()['z']; + + if (seg_score < 1 && suppressLowScores) { + return null; + } else { + return tipLayerStyles.tipStyle(feature, resolution); + } +} + + +(function () { + "use strict"; + + let $crashData = $('#crash-data'); + + function getCrashData(pdpId) { + $crashData.html(''); + + $.get('getcrash', {pdpId: pdpId}, function (d) { + $crashData.html(d); + }, 'text') + } + + // add the cell classes + $('.param-val').each(function () { + let z = parseFloat($(this).attr('data-crumb')); + let cellClass = 'cell-max'; + + if (z < -2.5) { + cellClass = 'cell-min'; + } else if (z < -1.5) { + cellClass = 'cell-very-low'; + } else if (z < -0.5) { + cellClass = 'cell-low'; + } else if (z < 0.5) { + cellClass = 'cell-mid'; + } else if (z < 1.5) { + cellClass = 'cell-high'; + } else if (z < 2.5) { + cellClass = 'cell-very-high'; + } + + $(this).addClass(cellClass); + }); + + let map = quickMap({center: {x: -10012438, y: 5548095}, zoom: 6, minZoom: 6}); + + let wisDotRegions = new LayerEsriMapServer( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/MetaManager/Metamanager_regions/MapServer', + { + minZoom: 6, + maxZoom: 15, + opacity: 0.4 + }); + + map.addLayer(wisDotRegions.olLayer); + + let reportSegments = new LayerBaseVectorGeoJson('', + { + loadCallback: function (theLayer) { + map.getView().fit(theLayer.source.getExtent(), map.getSize()); + }, + transform: {featureProjection: 'EPSG:3857', dataProjection: 'EPSG:3857'}, + style: tipStyleReport, + params: {d: (new Date()).getTime().toString()}, + zIndex: 10 + } + ); + + let geoJsonData = JSON.parse($('#geojson-data').val()); + reportSegments.addFeatures(geoJsonData); + + map.addLayer(reportSegments.olLayer); + map.getView().fit(reportSegments.source.getExtent(), map.getSize()); + + let itsLayerCollection = new ItsLayerCollection(map); + + for (let l of itsLayerCollection.layers) { + l.zIndex = 10; + l.opacity = 0.5; + } + + let layerArray = [ + { + groupName: 'ITS Inventory Layers', + collapse: true, + addCheck: true, + items: itsLayerCollection.layers + } + ]; + + let legend = new LayerLegend(layerArray, 'legend-container', {}); + + let $resultsTable = $('#results-table'); + let $resultsContainer = $('#results-container'); + + + + mapPopup.addMapClickFunction(function () { + $('.selected-row').removeClass('selected-row'); + }); + + //return undefined in popup callback to prevent default popup display + let selectionLayer = mapPopup.addVectorPopup(reportSegments, function (props) { + let pdp = props['p']; + getCrashData(pdp); + let $selectedRow = $resultsTable.find(`#${pdp}`); + $selectedRow.addClass('selected-row'); + $resultsContainer.find('table tbody').scrollTop(0); + $resultsContainer.find('table tbody').scrollTop($selectedRow.offset().top - 60); + return undefined; + }, + {olStyle: tipLayerStyles.tipStyleSelection} + ); + + mapPopup.addMapClickFunction(function () { + $crashData.html(''); + }); + + $('.selectable-row').click(function () { + let mapView = map.getView(); + selectionLayer.getSource().clear(); + $('.selected-row').removeClass('selected-row'); + $(this).addClass('selected-row'); + let pdp = parseInt(this.id); + let feats = reportSegments.source.getFeatures(); + getCrashData(pdp); + for (let feature of feats) { + if (feature.getProperties()['p'] == pdp) { + selectionLayer.getSource().addFeature(feature); + mapView.fit(feature.getGeometry().getExtent(), map.getSize()); + mapView.setZoom(mapView.getZoom() - 2); + return; + } + } + }); + + let $scoreUnderOneRows = $('.score-under-one-flag'); + + $('#show-all-toggle').click(function () { + if (this.checked) { + $scoreUnderOneRows.removeClass('score-under-one'); + suppressLowScores = false; + } else { + $scoreUnderOneRows.addClass('score-under-one'); + suppressLowScores = true; + } + reportSegments.refresh(); + mapPopup.closePopup(); + $('.selected-row').removeClass('selected-row'); + $('#crash-table').html(''); + + }).prop('checked', false); + + let oneRowTd = $resultsTable.find('tr:nth-of-type(2)').children('td'); + let $firstTrTh = $resultsTable.find('tr:first-of-type').children('th'); + + function updateTableColumnWidth(){ + + let colWidths = []; + + $firstTrTh.each(function(i, el){ + colWidths.push($(el).width()); + }); + + oneRowTd.each(function(i, el){ + $(el).width(colWidths[i]); + }); + } + + updateTableColumnWidth(); + + $resultsTable.find('tr:first-of-type').click(function(){ + setTimeout(updateTableColumnWidth, 50); + + }); + + +})(); diff --git a/projects/tsmo/main-ui.js b/projects/tsmo/main-ui.js new file mode 100644 index 0000000000000000000000000000000000000000..48be215361fda62917210e195d6fbd79426932b0 --- /dev/null +++ b/projects/tsmo/main-ui.js @@ -0,0 +1,126 @@ +/** + * Created by gavorhes on 12/14/2015. + */ +import tipConfig from './TipConfig'; +import mapMove from '../../src/olHelpers/mapMove'; +import LayerLegend from '../../src/collections/LayerLegend'; +const $ = require('jquery'); + +/** + * start the UI setup + */ +export function startUi() { + + tipConfig.$loadingGif = $('#loading-gif'); + tipConfig.$loadingGif.fadeIn(); + + tipConfig.$regionSelector = $('#region-selector'); + tipConfig.$regionSelector.val('all'); + + // configure the preset selector + let $presetSelector = $('#preset-selector'); + for (let i = 0; i < tipConfig._presetArray.length; i++) { + let weights = {}; + let sumCheck = 0; + for (let j = 0; j < tipConfig._sliderParamArray.length; j++) { + sumCheck += tipConfig._presetArray[i][1][j][0]; + weights[tipConfig._sliderParamArray[j][0].toLowerCase().replace(/ /g, '-')] = tipConfig._presetArray[i][1][j]; + } + if (sumCheck != 100) { + alert('Sum not equal to 100 for preset ' + tipConfig._presetArray[i][0]); + } + + let optionHtml = '<option value="'; + optionHtml += JSON.stringify(weights).replace(/"/g, '"'); + optionHtml += '"'; + optionHtml += (i == 0 ? ' selected="selected"' : '') + '>' + tipConfig._presetArray[i][0] + '</option>'; + + $presetSelector.append(optionHtml); + } + + //enable get help button + $('#tip-help').click(function () { + + let win = window.open('tip/help', '_blank'); + if (win) { + //Browser has allowed it to be opened + win.focus(); + } else { + //Browser has blocked it + alert('Please allow popups for this site'); + } + }); +} + + +/** + * finish the UI setup + */ +export function endUi() { + tipConfig.$loadingGif.fadeOut(); + + $('#make-report').click(function () { + let params = mapMove.mapExtent; + params['paramWeights'] = JSON.stringify(tipConfig.sliders.getParams()); + params['region'] = $('#region-selector').val(); + params['preset'] = $('#preset-selector option:selected').text(); + + let win = window.open('tip/getreport?' + $.param(params), '_blank'); + if (win) { + //Browser has allowed it to be opened + win.focus(); + } else { + //Browser has blocked it + alert('Please allow popups for this site'); + } + }); + + //add events to the preset selector + let $presetSelector = $('#preset-selector'); + + // add preset selector change handler + let first = true; + $presetSelector.change(function () { + + var weightSelection = JSON.parse(this.value); + tipConfig.sliders.setValues(weightSelection); + if (first) { + first = false; + } else { + mapMove.triggerLyrLoad(tipConfig.tipSegmentLayer); + } + }); + + $presetSelector.trigger('change'); + + $('#region-selector').change(function(){ + "use strict"; + mapMove.triggerLyrLoad(tipConfig.tipSegmentLayer); + }); + + + tipConfig.sliders.addSlideFinishedFunction(function () { + $presetSelector[0].selectedIndex = 0; + mapMove.triggerLyrLoad(tipConfig.tipSegmentLayer); + }); +} + +export function endUiMap() { + + mapMove.addCallback(function (ext, zoom, evt) { + $('#make-report').prop('disabled', !(zoom >= tipConfig.tipSegmentLayerMinZoom)); + }); + + let layerArray = [ + tipConfig.tipSegmentLayer, + tipConfig.metamanagerSegments, + { + groupName: 'ITS Inventory Layers', + collapse: true, + addCheck: false, + items: tipConfig.itsLayerCollection.layers + } + ]; + + let legend = new LayerLegend(layerArray, 'legend-container', {}); +} diff --git a/projects/tsmo/main.js b/projects/tsmo/main.js new file mode 100644 index 0000000000000000000000000000000000000000..3a73607be42fef3053324fbb9fc39728e370899d --- /dev/null +++ b/projects/tsmo/main.js @@ -0,0 +1,166 @@ +/** + * Created by gavorhes on 12/14/2015. + */ +import Sliders from '../../src/collections/Sliders'; +import tipConfig from './TipConfig'; +import mapPopup from '../../src/olHelpers/mapPopup'; +import * as uiSetup from './main-ui'; +import LayerEsriMapServer from '../../src/layers/LayerEsriMapServer'; +import ItsLayerCollection from '../../src/collections/ItsLayerCollection'; +import quickMap from '../../src/olHelpers/quickMap'; +import TipSegmentLayer from './TipSegmentLayer'; + +(function () { + "use strict"; + + glob.config = tipConfig; + + uiSetup.startUi(); + + let sliders = new Sliders(tipConfig._sliderParamArray, 'slider-container'); + tipConfig.sliders = sliders; + + let map = quickMap({minZoom: 7}); + + tipConfig.map = map; + + let wisDotRegions = new LayerEsriMapServer( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/MetaManager/Metamanager_regions/MapServer', + { + minZoom: 6, + maxZoom: 12, + name: 'WisDOT Regions', + useEsriStyle: true + }); + + map.addLayer(wisDotRegions.olLayer); + + //initialize the tip segment layer + let tipSegmentLayer = new TipSegmentLayer(sliders, + { + selectionStyle: { + color: 'rgba(0,0,255,0.5)', + width: 7 + }, + $loadingGif: tipConfig.$loadingGif, + $regionSelector: tipConfig.$regionSelector + } + ); + map.addLayer(tipSegmentLayer.olLayer); + tipConfig.tipSegmentLayer = tipSegmentLayer; + + let metamanagerSegments = new LayerEsriMapServer( + 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/MetaManager/MM_All_Segments/MapServer', + { + minZoom: 7, + visible: false, + name: 'Metamanager Segments' + }); + + map.addLayer(metamanagerSegments.olLayer); + tipConfig.metamanagerSegments = metamanagerSegments; + + //initialize the ITS layer collection + tipConfig.itsLayerCollection = new ItsLayerCollection(map); + + uiSetup.endUi(); + uiSetup.endUiMap(); + +})(); + + +// +//let sliders; +// let app; +// let extraLayers = {}; +// +// $(function () { +// return; +// // create the sliders object +// sliders = new SliderGroup(tipConfig._sliderParamArray, 'slider-container'); +// +// $('#btnResetDefault').click(function () { +// sliders.reset(); +// }); +// + +// +// let geoJsonArray = []; +// +// for (i = 0; i < itsLayerConfig.length; i++) { +// geoJsonArray.push(new ItsGeoJsonLayer(itsLayerConfig[i], app.map, 'its-legend-items')); +// } +// +// $('#showVis').prop('checked', true); +// +// $('input[name=showAll]').change(function () { +// let $legendDivs = $('#its-legend-items > div'); +// if (this.id == 'showAll' && this.checked) { +// $legendDivs.addClass('force-show'); +// } else { +// $legendDivs.removeClass('force-show'); +// } +// }); +// +// function showHide() { +// let shown = true; +// let $legend = $('#its-legend-items'); +// let $pic = $('#show-hide'); +// return function () { +// if (shown) { +// $legend.slideUp(); +// shown = false; +// $pic.attr('src', $pic.attr('src').replace('up', 'down')); +// } else { +// $legend.slideDown(); +// shown = true; +// $pic.attr('src', $pic.attr('src').replace('down', 'up')); +// } +// } +// } +// +// +// $('#show-hide').click(showHide()).trigger('click'); +// +// $('#show-hide-all-its').prop('checked', true).change(function () { +// +// for (let i = 0; i < geoJsonArray.length; i++) { +// geoJsonArray[i].groupVisible = this.checked; +// } +// +// }); +// +// +// let url = 'http://transportal.cee.wisc.edu/applications/arcgis2/rest/services/MetaManager/MM_All_Segments/MapServer'; +// +// extraLayers['mm-layer'] = new ol.layer.Tile({ +// source: new ol.source.TileArcGISRest({ +// url: url +// }) +// }); +// +// let layerCheckboxes = $('#layer-switch').find('input[type="checkbox"]'); +// +// layerCheckboxes.each(function (idx, val) { +// val.checked = false; +// }); +// +// layerCheckboxes.click(function () { +// if (this.checked) { +// app.map.addLayer(extraLayers[this.id]) +// } else { +// app.map.removeLayer(extraLayers[this.id]) +// } +// }); +// +// //fade out the loading gif when complete +// $gif.fadeOut(); +// + +// + +// }); + + + + diff --git a/projects/tsmo/slider-test.js b/projects/tsmo/slider-test.js new file mode 100644 index 0000000000000000000000000000000000000000..6bf939d2b395e422fde1a898ff5ce6b7dfdc7523 --- /dev/null +++ b/projects/tsmo/slider-test.js @@ -0,0 +1,29 @@ +/** + * Created by gavorhes on 12/14/2015. + */ + +import Sliders from '../../src/collections/Sliders'; +import {} from '../../src/jquery-plugin/dayRange'; +import tipConfig from './TipConfig'; +const $ = require('jquery'); + +(function(){ + //alert('here'); + + let dayRange = $('#dates').dayRange(10); + + + //let sliders = new Sliders(tipConfig._sliderParamArray, 'slider-container'); + //glob.sliders = sliders; + // + // + // + // + //console.log(tipConfig); +})(); + + + + + + diff --git a/projects/tsmo/tipStyleFunction.js b/projects/tsmo/tipStyleFunction.js new file mode 100644 index 0000000000000000000000000000000000000000..33d6c2f262ed33015c29c3a06307a397af0790c9 --- /dev/null +++ b/projects/tsmo/tipStyleFunction.js @@ -0,0 +1,84 @@ +/** + * Created by gavorhes on 12/22/2015. + */ +import * as zoomResolutionConvert from '../../src/olHelpers/zoomResolutionConvert'; +import ol from '../../src/custom-ol'; + + +/** + * tip style function + * @param feature + * @param resolution + * @returns {*[]} + */ +export function tipStyle(feature, resolution) { + + let zoom = zoomResolutionConvert.resolutionToZoom(resolution); + + let width = 5; + + if (zoom >= 18){ + width = 10; + } else if (zoom >= 14) { + width = 8; + } else if (zoom >= 12) { + width = 7; + } else if (zoom >= 10) { + width = 6; + } + + let seg_score = feature.getProperties()['z']; + let hex_color; + if (seg_score < -2.5) { + hex_color = '#00ff00'; + } else if (seg_score < -1.5) { + hex_color = '#55ff00'; + } else if (seg_score < -0.5) { + hex_color = '#aaff00'; + } else if (seg_score < 0.5) { + hex_color = '#ffff00'; + } else if (seg_score < 1.5) { + hex_color = '#ffaa00'; + } else if (seg_score < 2.5) { + hex_color = '#ff5500'; + } else { + hex_color = '#ff0000' + } + + return [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: hex_color, + width: width + }) + })]; +} + +/** + * selection style + * @param feature + * @param resolution + * @returns {*[]} + */ +export function tipStyleSelection (feature, resolution) { + + let zoom = zoomResolutionConvert.resolutionToZoom(resolution); + + let width = 5; + + if (zoom >= 18){ + width = 10; + } else if (zoom >= 14) { + width = 8; + } else if (zoom >= 12) { + width = 7; + } else if (zoom >= 10) { + width = 6; + } + + return [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#0074ff', + width: width + }) + })]; +} \ No newline at end of file diff --git a/src/collections/ItsLayerCollection.js b/src/collections/ItsLayerCollection.js index 78d40781ef13c7469e06d7555ad873f08d724857..d446ae3978ac1fd69e130175d74cda76ca84ddb2 100644 --- a/src/collections/ItsLayerCollection.js +++ b/src/collections/ItsLayerCollection.js @@ -123,7 +123,7 @@ class ItsLayerCollection { /** * Create a collection of all ITS layers - * @param {Map} theMap the openlayers map + * @param {ol.Map} theMap the openlayers map * @param {Array} [exclude=[]] array of Its layer identifiers to exclude * * BLUE Bluetooth Detector - Bluetooth Detector diff --git a/src/collections/LayerLegend.js b/src/collections/LayerLegend.js index 6d7bb329006305e1be9b5ad88544ae2a72fa1153..d8526850460bf073231053d387f822778ec2b8cc 100644 --- a/src/collections/LayerLegend.js +++ b/src/collections/LayerLegend.js @@ -1,7 +1,7 @@ /** * Created by gavorhes on 12/16/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import provide from '../util/provide'; import makeGuid from '../util/makeGuid'; import mapMove from '../olHelpers/mapMove'; diff --git a/src/collections/Sliders.js b/src/collections/Sliders.js index 3ea46e358ceba175f01f7ca63cb9bfe5c7afd325..6254f48dd6c71e14660f8a42847b1cb41af5e977 100644 --- a/src/collections/Sliders.js +++ b/src/collections/Sliders.js @@ -3,7 +3,7 @@ */ import provide from '../util/provide'; let nm = provide('collections'); -let $ = require('jquery'); +import $ from '../jquery'; class _Slider { diff --git a/src/jquery-plugin/dayRange.js b/src/jquery-plugin/dayRange.js index 21037cddb487ad792c7d12391890fcf091a9efc0..75b3b515e31d698daa0ce0fa8f53ec37b58204ca 100644 --- a/src/jquery-plugin/dayRange.js +++ b/src/jquery-plugin/dayRange.js @@ -1,4 +1,4 @@ -let $ = require('jquery'); +import $ from '../jquery'; require('jquery-ui/datepicker'); import provide from '../util/provide'; let nm = provide('jQueryPlugin'); diff --git a/src/jquery-plugin/mediaControl.js b/src/jquery-plugin/mediaControl.js index 10565eac19b4e573422a5d37e07a664a83018cde..5fbe63aefa9bfdf0c94f1371ccda053d66223e35 100644 --- a/src/jquery-plugin/mediaControl.js +++ b/src/jquery-plugin/mediaControl.js @@ -1,4 +1,4 @@ -const $ = require('jquery'); +import $ from '../jquery'; import provide from '../util/provide'; let nm = provide('jQueryPlugin'); diff --git a/src/jquery-plugin/rangeChange.js b/src/jquery-plugin/rangeChange.js index 19d8f69b241cc88343f9003707751fe206bf2b88..eea8b887fe1ee65b007acf17f004d488cfedb0dc 100644 --- a/src/jquery-plugin/rangeChange.js +++ b/src/jquery-plugin/rangeChange.js @@ -4,7 +4,7 @@ * Created by gavorhes on 11/2/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; let mouseIn = false; let mouseDown = false; let timeout = null; diff --git a/src/jquery-plugin/rpPicker.js b/src/jquery-plugin/rpPicker.js index dc7d9586733babe6792346c777fb8c15047d77df..05ffd495216cec300b2e9277fe5031d8113db9e5 100644 --- a/src/jquery-plugin/rpPicker.js +++ b/src/jquery-plugin/rpPicker.js @@ -1,4 +1,4 @@ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import quickMap from '../olHelpers/quickMap'; diff --git a/src/jquery-plugin/ssaCorridorPicker.js b/src/jquery-plugin/ssaCorridorPicker.js index eaded167b22e150df80579251386e2e949217f26..67855fb46976609139b2ed524c309de59a9ba49c 100644 --- a/src/jquery-plugin/ssaCorridorPicker.js +++ b/src/jquery-plugin/ssaCorridorPicker.js @@ -1,4 +1,4 @@ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import quickMap from '../olHelpers/quickMap'; diff --git a/src/jquery.js b/src/jquery.js new file mode 100644 index 0000000000000000000000000000000000000000..c863dfde2f8fe7d5dc7916d3711bcef5368b8ecf --- /dev/null +++ b/src/jquery.js @@ -0,0 +1,6 @@ +/** + * Created by gavorhes on 5/3/2016. + */ +const $ = require('jquery/dist/jquery.min'); + +export default $; diff --git a/src/layers/LayerBase.js b/src/layers/LayerBase.js index ed07436559c94fe7e060a59e885fe646d0a8ca01..699e4a96f13667a9c28b76f05fc6f5e6cf3a73b5 100644 --- a/src/layers/LayerBase.js +++ b/src/layers/LayerBase.js @@ -1,4 +1,4 @@ -const $ = require('jquery'); +import $ from '../jquery'; import makeGuid from '../util/makeGuid'; import * as zoomResolutionConvert from '../olHelpers/zoomResolutionConvert'; import provide from '../util/provide'; diff --git a/src/layers/LayerBaseVector.js b/src/layers/LayerBaseVector.js index 70af8274212c8afbd2004a2bda8b1e855ae9ff63..8dc214ae8f3ad7b4180892971876e16dddd85361 100644 --- a/src/layers/LayerBaseVector.js +++ b/src/layers/LayerBaseVector.js @@ -1,4 +1,4 @@ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBase from './LayerBase'; import mapMove from '../olHelpers/mapMove'; @@ -183,7 +183,7 @@ class LayerBaseVector extends LayerBase { /** * get the style definition - * @type {ol.Style|function} + * @type {ol.Style|styleFunc} */ get style() { return this._style; diff --git a/src/layers/LayerBaseVectorEsri.js b/src/layers/LayerBaseVectorEsri.js index 941cd3a6c2de4da8912a57c4c26107922393e0ab..70862a35bc3ca20244b9b284d1b1f13c1df86f02 100644 --- a/src/layers/LayerBaseVectorEsri.js +++ b/src/layers/LayerBaseVectorEsri.js @@ -1,7 +1,7 @@ /** * Created by gavorhes on 11/2/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBaseVector from './LayerBaseVector'; import * as esriToOl from '../olHelpers/esriToOlStyle'; diff --git a/src/layers/LayerBaseVectorGeoJson.js b/src/layers/LayerBaseVectorGeoJson.js index 73c381c1fe76d0c3bcd0029ddf57b87f50e2bedd..884a280b8d73dee149904398de5a42c93c17bf69 100644 --- a/src/layers/LayerBaseVectorGeoJson.js +++ b/src/layers/LayerBaseVectorGeoJson.js @@ -1,7 +1,7 @@ /** * Created by gavorhes on 11/2/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBaseVector from './LayerBaseVector'; import provide from '../util/provide'; diff --git a/src/layers/LayerBaseXyzTile.js b/src/layers/LayerBaseXyzTile.js index 3ccefd89a1dc0ae847cffc6fbc915f8b0ad00c09..5b6ec6ebf37bd8105ccec6d15f87e31723b878e9 100644 --- a/src/layers/LayerBaseXyzTile.js +++ b/src/layers/LayerBaseXyzTile.js @@ -1,7 +1,7 @@ /** * Created by gavorhes on 12/4/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBase from './LayerBase'; import * as esriToOl from '../olHelpers/esriToOlStyle'; diff --git a/src/layers/LayerEsriMapServer.js b/src/layers/LayerEsriMapServer.js index 47a23d5bbafae211f13f35fe3ac32da8e03ed766..759775abdde1237b9a1acbe30066ae5de4e812b0 100644 --- a/src/layers/LayerEsriMapServer.js +++ b/src/layers/LayerEsriMapServer.js @@ -1,7 +1,7 @@ /** * Created by gavorhes on 12/7/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBase from './LayerBase'; import * as esriToOl from '../olHelpers/esriToOlStyle'; diff --git a/src/layers/LayerItsInventory.js b/src/layers/LayerItsInventory.js index cb793ff76363300e1a42061579f5d9638ba03cde..e4405436e30a8fa1842918f47669c3730f06fda1 100644 --- a/src/layers/LayerItsInventory.js +++ b/src/layers/LayerItsInventory.js @@ -2,7 +2,7 @@ * Created by gavorhes on 12/8/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import LayerBaseVectorGeoJson from './LayerBaseVectorGeoJson'; import mapMove from '../olHelpers/mapMove'; diff --git a/src/layers/LayerRealEarthTile.js b/src/layers/LayerRealEarthTile.js index c7bdddda6528d8f9469d9ece223e851ea52caa3a..de867095bb3feb82c85250bf1e121f566ab5e80d 100644 --- a/src/layers/LayerRealEarthTile.js +++ b/src/layers/LayerRealEarthTile.js @@ -2,7 +2,7 @@ * Created by gavorhes on 11/4/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import LayerBaseXyzTile from './LayerBaseXyzTile'; import RealEarthAnimateTile from '../mixin/RealEarthAnimateTile'; let mixIns = require('es6-mixins'); diff --git a/src/mixin/RealEarthAnimate.js b/src/mixin/RealEarthAnimate.js index 900105d72c679d8ba991953a638571d16ae8d36f..d2f38fc576a04fcd4f962490b1bf59fe9ef2b9c1 100644 --- a/src/mixin/RealEarthAnimate.js +++ b/src/mixin/RealEarthAnimate.js @@ -3,7 +3,7 @@ */ import provide from '../util/provide'; import mapPopup from '../olHelpers/mapPopup'; -const $ = require('jquery'); +import $ from '../jquery'; let nm = provide('mixin'); diff --git a/src/olHelpers/mapMoveCls.js b/src/olHelpers/mapMoveCls.js index c93ba7f06549f898fe53347a78117bb0c58cf9b8..127ac8b64f8d5525341d010331ad9901d37e9e0e 100644 --- a/src/olHelpers/mapMoveCls.js +++ b/src/olHelpers/mapMoveCls.js @@ -3,7 +3,7 @@ */ -const $ = require('jquery'); +import $ from '../jquery'; import MapInteractionBase from './mapInteractionBase'; import * as checkDefined from '../util/checkDefined'; import provide from '../util/provide'; diff --git a/src/olHelpers/mapPopupCls.js b/src/olHelpers/mapPopupCls.js index 86c92562cc661ad6c6f3a79e89d3de39a73083d0..8519140d138de1b8f4d443f9fc9c312e139ff411 100644 --- a/src/olHelpers/mapPopupCls.js +++ b/src/olHelpers/mapPopupCls.js @@ -2,7 +2,7 @@ * Created by gavorhes on 11/3/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import MapInteractionBase from './mapInteractionBase'; import propertiesZoomStyle from '../olHelpers/propertiesZoomStyle'; diff --git a/src/olHelpers/quickMapBase.js b/src/olHelpers/quickMapBase.js index 099014061fd1718d3eb83d7aa79e6ca29e5a9ce8..338af5717ce9b93ad5a84d4e0b73cec307e050e3 100644 --- a/src/olHelpers/quickMapBase.js +++ b/src/olHelpers/quickMapBase.js @@ -6,7 +6,7 @@ * Created by gavorhes on 12/15/2015. */ -const $ = require('jquery'); +import $ from '../jquery'; import ol from '../custom-ol'; import provide from '../util/provide'; import mapMove from './mapMove';