// The MIT License (MIT)
//
// Copyright (c) 2019-2022 Camptocamp SA
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* @module Mask.js
* @name Mask
*/
import Layer from 'ol/layer/Layer.js';
import {createCanvasContext2D} from 'ol/dom.js';
import {toRadians} from 'ol/math.js';
import {FrameState} from 'ol/Map.js'
/**
* @class
* @name Mask
* @augments Layer
*/
export default class Mask extends Layer {
constructor(options = {}) {
super(options);
/**
* @private
*/
this.context_ = createCanvasContext2D();
this.context_.canvas.style.opacity = '0.5';
this.context_.canvas.style.position = 'absolute';
/**
* Provide scale (number) from FrameState
* @function
*/
this.getScale;
/**
* Provide the size of type import('ol/size').Size
* @function
*/
this.getSize;
/**
* Provide the rotation
* @type {undefined|Function}
*/
this.getRotation;
}
/**
* Render function. Takes the frame state as input and is expected to return an HTML element. Will overwrite the default rendering for the layer.
* @param {FrameState} frameState Frame state
* @returns {HTMLElement} The rendered element
*/
render(frameState) {
const INCHES_PER_METER = 39.37;
const DOTS_PER_INCH = 72;
const cwidth = frameState.size[0];
this.context_.canvas.width = cwidth;
const cheight = frameState.size[1];
this.context_.canvas.height = cheight;
const center = [cwidth / 2, cheight / 2];
// background (clockwise)
this.context_.beginPath();
this.context_.moveTo(-1, -1);
this.context_.lineTo(cwidth+1, -1);
this.context_.lineTo(cwidth+1, cheight+1);
this.context_.lineTo(-1, cheight+1);
this.context_.lineTo(-1, -1);
this.context_.closePath();
const size = this.getSize();
const height = size[1];
const width = size[0];
const scale = this.getScale(frameState);
const resolution = frameState.viewState.resolution;
const extentHalfWidth = ((width / DOTS_PER_INCH / INCHES_PER_METER) * scale) / resolution / 2;
const extentHalfHeight = ((height / DOTS_PER_INCH / INCHES_PER_METER) * scale) / resolution / 2;
const rotation = this.getRotation !== undefined ? toRadians(this.getRotation()) : 0;
// diagonal = distance p1 to center.
const diagonal = Math.sqrt(Math.pow(extentHalfWidth, 2) + Math.pow(extentHalfHeight, 2));
// gamma = angle between horizontal and diagonal (with rotation).
const gamma = Math.atan(extentHalfHeight / extentHalfWidth) - rotation;
// omega = angle between diagonal and vertical (with rotation).
// NOT USED const omega = Math.atan(extentHalfWidth / extentHalfHeight) - rotation;
// Calculation of up left corner.
const x1 = Math.round(center[0] - Math.cos(gamma) * diagonal);
const y1 = Math.round(center[1] + Math.sin(gamma) * diagonal);
// Calculation of down right corner
const x2 = Math.round(center[0] + Math.cos(gamma) * diagonal);
const y2 = Math.round(center[1] - Math.sin(gamma) * diagonal);
// hole (counter-clockwise)
this.context_.moveTo(x1, y1);
this.context_.lineTo(x2, y1);
this.context_.lineTo(x2, y2);
this.context_.lineTo(x1, y2);
this.context_.lineTo(x1, y1);
this.context_.closePath();
this.context_.fillStyle = '#000';
this.context_.fill();
return this.context_.canvas;
}
}