| /* |
| * Copyright 2015-present Open Networking Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| import { Injectable } from '@angular/core'; |
| import { FnService } from '../util/fn.service'; |
| import { LogService } from '../../log.service'; |
| import { ThemeService } from '../util/theme.service'; |
| import { WebSocketService } from '../remote/websocket.service'; |
| import * as d3 from 'd3'; |
| |
| const id = 'loading-anim'; |
| const dir = 'data/img/loading/'; |
| const pfx = '/load-'; |
| const nImgs = 16; |
| const speed = 100; |
| const waitDelay = 500; |
| |
| |
| /** |
| * ONOS GUI -- Layer -- Loading Service |
| * |
| * Provides a mechanism to start/stop the loading animation, center screen. |
| */ |
| @Injectable() |
| export class LoadingService { |
| images: any[] = []; |
| idx = 0; |
| img: any; |
| theme: string; |
| task: any; |
| wait: number; |
| |
| constructor( |
| private fs: FnService, |
| private log: LogService, |
| private ts: ThemeService, |
| private wss: WebSocketService |
| ) { |
| this.preloadImages(); |
| this.log.debug('LoadingService constructed'); |
| } |
| |
| dbg(...args) { |
| this.fs.debug(this.constructor.name, args); |
| } |
| |
| preloadImages() { |
| let idx: number; |
| |
| this.dbg('preload images start...'); |
| for (idx = 1; idx <= nImgs ; idx++) { |
| this.addImg('light', idx); |
| this.addImg('dark', idx); |
| } |
| this.dbg('preload images DONE!', this.images); |
| } |
| |
| addImg(theme: string, idx: number) { |
| const img = new Image(); |
| img.src = this.fname(idx, theme); |
| this.images.push(img); |
| } |
| |
| fname(i: number, theme: string) { |
| const z = i > 9 ? '' : '0'; |
| return dir + theme + pfx + z + i + '.png'; |
| } |
| |
| nextFrame() { |
| this.idx = this.idx === 16 ? 1 : this.idx + 1; |
| this.img.attr('src', this.fname(this.idx, this.theme)); |
| } |
| |
| // start displaying 'loading...' animation (idempotent) |
| startAnim() { |
| this.dbg('start ANIMATION'); |
| this.theme = this.ts.getTheme(); |
| let div = d3.select('#' + id); |
| if (div.empty()) { |
| div = d3.select('body') |
| .append('div') |
| .attr('id', id); |
| this.img = div |
| .append('img') |
| .attr('src', this.fname(1, this.theme)); |
| this.idx = 1; |
| this.task = setInterval(() => this.nextFrame(), speed); |
| } |
| } |
| |
| // stop displaying 'loading...' animation (idempotent) |
| stopAnim() { |
| this.dbg('*stop* ANIMATION'); |
| if (this.task) { |
| clearInterval(this.task); |
| this.task = null; |
| } |
| d3.select('#' + id).remove(); |
| } |
| |
| // schedule function to start animation in the future |
| start() { |
| this.dbg('start (schedule)'); |
| this.wait = setTimeout(this.startAnim(), waitDelay); |
| } |
| |
| // cancel future start, if any; stop the animation |
| stop() { |
| if (this.wait) { |
| this.dbg('start CANCELED'); |
| clearTimeout(this.wait); |
| this.wait = null; |
| } |
| this.stopAnim(); |
| } |
| |
| // return true if start() has been called but not stop() |
| waiting() { |
| return !!this.wait; |
| } |
| |
| |
| } |