Draw a border inside video with angular and CSS - html

I am writing a SPA which very simply shows video from webcam, draws a rectangle on it (so you can place a document where the edges align with the drawn box) then I press a button to capture that image.
Everything works except for drawing the box. I want it to be somewhat inside the div, so it's not around the video but actually on the video, aligning the sides but with a, let's say, 25px difference. I now just draw a border with CSS but I'm guessing there's better solutions I just can't seem to find them.
Edit: I tried with the drawImge() - function too, didn't seem to find a way to make it work. Haven't figured out why though.
app.component.ts:
import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
#ViewChild('video', { static: true }) videoElement: ElementRef;
#ViewChild('canvas', { static: true }) canvas: ElementRef;
videoWidth = 0;
videoHeight = 0;
constraints = {
video: {
facingMode: "environment",
width: { ideal: 4096 },
height: { ideal: 2160 }
}
};
constructor(private renderer: Renderer2) {}
ngOnInit() {
this.startCamera();
}
startCamera() {
if (!!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) {
navigator.mediaDevices.getUserMedia(this.constraints).then(this.attachVideo.bind(this))
.catch(this.handleError);
} else {
alert('Sorry, camera not available.');
}
}
attachVideo(stream) {
this.renderer.setProperty(this.videoElement.nativeElement, 'srcObject', stream);
this.renderer.listen(this.videoElement.nativeElement, 'play', (event) => {
this.videoHeight = this.videoElement.nativeElement.videoHeight;
this.videoWidth = this.videoElement.nativeElement.videoWidth;
});
}
capture() {
this.renderer.setProperty(this.canvas.nativeElement, 'width', this.videoWidth);
this.renderer.setProperty(this.canvas.nativeElement, 'height', this.videoHeight);
this.canvas.nativeElement.getContext('2d').drawImage(this.videoElement.nativeElement, 0, 0);
}
drawImge(videoHeight, videoWidth){
var video = document.querySelector("#webCamera");
var canvas = document.querySelector("#videoCanvas");
var ctx = this.canvas.nativeElement.getContext('2d');
ctx.rect(0,0,videoWidth,videoHeight);
ctx.lineWidth = "6";
ctx.strokeStyle = "red";
ctx.stroke();
}
handleError(error) {
console.log('Error: ', error);
}
}
app.component.html
<div class="container vh-100">
<div class="d-flex flex-column align-items-center">
<div class="p-1" >
<video #video class="vid" id="canvas1" autoplay></video>
</div>
<div class="pb-2">
<button class="btn btn-primary" (click)="capture()">Capture Image</button>
</div>
<div class="p-1">
<canvas #canvas class="vid"></canvas>
</div>
</div>
</div>
app.component.scss
#canvas1{
border-style: inset;
border-width: 300px;
border: solid 3px green;
}

Ok guys,
I found a really easy solution with CSS, it is however a bit messy as it's hardcoded. Also all the other drawings on screen should be animateable. Meaning i.e. an arrow drawn on screen moving slightly up, resetting and making the motion again untill someone uses the capture button.
This to only say I'm still looking for a solution that's not just CSS if anyone might have one.
As for the solution:
app.component.html:
<div class="container vh-100">
<div class="d-flex flex-column align-items-center">
<div class="p-1 wrapper" >
<video #video class="vid" id="canvas1" autoplay></video>
<div class="trapeziod"></div>
<div class="rect"></div>
</div>
<div class="pb-2">
<button class="btn btn-primary" (click)="capture()">Capture Image</button>
</div>
<div class="p-1">
<canvas #canvas class="vid"></canvas>
</div>
</div>
</div>
So just another div in the div where the video resides, called rect.
Then:
app.component.scss
#canvas1{
border-style: inset;
border-width: 300px;
border: solid 2px black;
}
.trapezoid {
width: 50px;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid #7FFF00;
}
.wrapper{
position: relative;
}
.rect{
position: absolute;
left: calc(10% - 90px);
top: calc(20% - 100px);
border: solid 8px #7FFF00;
width: 1060px;
height: 580px;
}
This is perfectly how it should look.

Related

Is there a way to change the appeareance of an html text when hovering on the div that contains it?

I need to color and zoom the text when the cursor "approaches" the text (so basically when the mouse enters the area of the div surrounding the text). Right now i can make it work coloring the text only when i hover directly on it. I'll paste a snippet of the code.
HTML:
<div fxLayout="row wrap" class="max container">
<div fxFlex="100%" fxLayoutAlign="center">
<!--here there is an image-->
</div>
<div fxFlex="100%" class="centered-text" fxHide fxShow.gt-lg>
<h2 [ngClass]="{'gradient' : this.gradient,'lighter':lighter, 'zoom':zoom, 'scale':1.2}" style="margin: 0;" class="font">
hoverMe
</h2>
</div>
</div>
Typescript:
import {Component, Input, OnInit} from '#angular/core';
#Component({
selector: 'iet-box-academy',
templateUrl: './box-academy.component.html',
styleUrls: ['./box-academy.component.scss']
})
export class BoxAcademyComponent implements OnInit {
#Input() scale = 1;
#Input() img = '';
#Input() title = 'TITOLO';
#Input() descr = '';
#Input() align = "centerer";
#Input() lighter = false;
#Input() zoom = true;
#Input() gradient: boolean = false;
constructor() {
}
ngOnInit(): void {
}
}
CSS:
.container {
position: relative;
text-align: center;
color: black;
}
.zoom {
transition: transform .2s; /* Animation */
margin: 0 auto;
}
.zoom:hover {
transform: scale(1.5);
color: #00D3FF;
}
https://jsfiddle.net/wdfc7g9a/14/
You can add the :hover to the parent and add a child selector:
Change:
.zoom:hover {
transform: scale(1.5);
color: #00D3FF;
}
To:
.container:hover .zoom {
transform: scale(1.5);
color: #00D3FF;
}
Demo:
.container {
border: 1px solid red;
}
.container:hover .zoom {
background: yellow;
}
<div class="container">
This is a text
<div class="zoom">highlight this text</div>
More text
</div>
I recommend you to use centered-text class instead of zoom class. Because it is easier to give a transparent padding to it so you can have the "approaching" animation played without needing to hover directly on the text.
This code will fix your problem the moment you copy paste it to your Custom CSS:
.centered-text {
transition: all 0.3s;
margin: 0 auto;
padding:13px;
}
.centered-text:hover {
transform: scale(1.4);
color: #00D3FF;
transition: all 0.3s;
}

trying to do a gallery with lightbox but does not pop up

I'm new on angular,
And I'm trying to make a gallery with a lighbox that shows up when an image is clicked.
I already try the examples with bootstrap and also tried to do it by myself, but when I click on the img-link, the links throws me up to the home page maybe there is a config that I didn't know how to use it or is missing.
I don't know if its a problem about routes or if I need to do other commponent for that.
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
import { Component, OnInit } from '#angular/core';
import { CuadrosService, Cuadro } from '../cuadros.service';
#Component({
selector: 'app-galeria',
templateUrl: './galeria.component.html',
styleUrls: ['./galeria.component.css']
})
export class GaleriaComponent implements OnInit {
Cuadro:any [] = [];
constructor(private _cuadosService:CuadrosService ) {
console.log("constructor")
}
ngOnInit(): void {
this.Cuadro = this._cuadosService.getCuadros();
console.log(this.Cuadro);
}
}
.container-galeria {
display: flex;
flex-wrap: wrap;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 400px;
background-color: rgba(0, 0, 0, .80);
justify-content: space-around;
}
.img-galeria {
width: 100%;
height: 100%;
object-fit: cover;
padding: 10px;
}
.img-galeria:hover {
transform: scale(1.05);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.3);
}
.item-galeria:nth-child(1) {
grid-column-start: span 2;
}
.item-galeria:nth-child(2) {
grid-row-start: span 2;
}
.lightbox {}
.lightbox:active {
display: block;
position: fixed;
flex-wrap: wrap;
height: fit-content;
width: fit-content;
max-width: 1200px;
max-height: 800px;
background-color: rgba(0, 0, 0, 0.3);
z-index: 2000;
justify-content: center;
}
<hr>
<div class="container-galeria container">
<div class=" lighbox item-galeria col-4" *ngFor="let cuadro of Cuadro">
<img class="img-galeria" [src]="cuadro.foto" alt="">
</div>
</div>
<app-footer></app-footer>
Any idea? or somthing wrong in my code?
Thanks for the help.
So the way I am seeing it your lightbox is missing a t in the class name.
Secondly I would set a onclick listener for each image to remove and set an active class instead of using the :active css selector. The css selector :active will be removed as soon as the person stops clicking.
You will have to Pass your Element in to the function to determine what image will be active.
Also you might want to add a function to exit the active mode
<div class="lightbox item-galeria col-4" *ngFor="let cuadro of Cuadro" (click)="toggleActive($event, item)">
<img class="img-galeria" [src]="cuadro.foto" alt="">
</div>
The function:
import { Component, OnInit } from '#angular/core';
import { CuadrosService, Cuadro } from '../cuadros.service';
#Component({
selector: 'app-galeria',
templateUrl: './galeria.component.html',
styleUrls: ['./galeria.component.css']
})
export class GaleriaComponent implements OnInit {
Cuadro:any [] = [];
constructor(private _cuadosService:CuadrosService ) {
console.log("constructor")
}
ngOnInit(): void {
this.Cuadro = this._cuadosService.getCuadros();
console.log(this.Cuadro);
}
toggle(event, item): void {
if(item.classList.contains("active")){
item.classList.remove("active"));
}else{
item.classList.add("active"));
}
}
I might add that I didn't test the code and some parts of code may need a little tweak.
I hope I could help.

Scroll Event is not firing in Angular-6

I know this question is asked before, but none of the solutions worked for me.
I am working on the Angular-6 project. I am trying to get Window-Scroll event in one of the components named SectionComponent.
Styles of html and body tag:
html, body {
overflow: auto;
position: relative;
margin: 0;
height: 100%;
}
Below is the hierarchy of components which explains how components are managed.
My AppComponent:
HTML:
<div id="wrapper">
<router-outlet></router-outlet>
</div>
CSS:
#wrapper {
width: 100vw;
height: 100vh;
position: relative;
overflow: auto;
}
app.component.ts:
#HostListener('window:scroll', [])
onWindowScroll() {
console.log('scroll');
}
AppComponent loads component named HomeComponent in the router-outlet tag. This HomeComponent loads SectionComponent by using is selector.
My HomeComponent:
HTML:
<div class="home-wrapper">
<div>
<!-- Some content more that window height -->
</div>
<app-section></app-section>
</div>
CSS:
.home-wrapper {
position: relative;
overflow-y: auto;
height: 100%;
}
home.component.ts:
#HostListener('window:scroll', [])
onWindowScroll() {
console.log('scroll');
}
My SectionComponent
HTML:
<div class="section-wrapper">
<!-- Some content more than window height -->
</div>
CSS:
.section-wrapper {
position: relative;
height: 2241px;
}
section.component.ts:
#HostListener('window:scroll', [])
onWindowScroll() {
console.log('scroll');
}
I only want to use Window-Scroll in SectionComponent. But none of the components are firing the event. What am I doing wrong?
import { ScrollDispatcher } from '#angular/cdk/scrolling';
constructor(private scrollDispatcher: ScrollDispatcher) {
this.scrollDispatcher.scrolled().subscribe(x => console.log('I am scrolling'));
}
in tempalte:
<div cdkScrollable>
<div *ngFor="let one of manyToScrollThru">
{{one}}
</div>
</div>
In Your SectionComponent after the class declaration just use
#HostListener('window:scroll', ['$event']) onScrollEvent($event){
var element = document.getElementsByClassName('section-wrapper')[0];
var rect = element.getBoundingClientRect();
// the above code will return the CSS border-boxe associated with the element.
// so on scroll you will have readonly left, top, right, bottom, x, y, width, and height properties .
//on behalf of these properties you can manipulate the DOM section-wrapper div.
}

Slide a div from the bottom underneath another div with angular animations

As you can see in the screenshot below, I hava a tab on the bottom of my page. When I click on it, I want it to slide underneath the <div> containing "Test" using angular animations. The problem is, that the pagesize should be responsive and therefore I cannot use px-values. I tried percentage as well, but that value refers to my tab-div, not the overall height.
Screenshot
My component:
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss'],
animations: [
trigger('tabState', [state('default', style({
transform: 'translateY(0)'
})
),
state('open', style({
transform: 'translateY(-100%)'
})),
transition('default <=> open', animate(500))
])
]})
export class TestComponent {
state = 'default';
onComeIn() {
this.state === 'default' ? this.state = 'open' : this.state = 'default';
}
}
My HTML:
<div class="mainContainer">
<mat-toolbar color="primary">
<div class="d-flex align-items-center justify-content-between">
<span>Test</span>
</div>
</mat-toolbar>
<div class="mainContentContainer">
<div class="d-flex flex-column" style="height: 100%">
<div>content</div>
<div class="mt-auto">
<div class="tabContainer" [#tabState]="state">
<div class="tab" (click)="onComeIn()">Tab</div>
</div>
</div>
</div>
And finally the css:
.tab {
box-sizing: border-box;
height: 4.2em;
width: 33%;
background-color: white;
padding: 1em 1.2em 0.45em 1.2em;
border-radius: 0.5em 0.5em 0 0;
box-shadow: 0 0.05em #b7b7b7;
}
.mainContainer {
width: 100%;
display: flex;
flex-direction: column;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.mainContentContainer {
flex: 1;
background-color: #455864;
}
The issue is more about css :
I changed the initial value of the tabContainer class to this :
.tabContainer {
position: fixed;
bottom: 0;
width: 100%;
}
Then in the animation definition, removed the bottom and added the top one :
state('open', style({
bottom: 'initial',
top: '20px'
})),
Here is the running example in editor.

ngOnInit ignores CSS transition

I have div which I would like to have its width increase from 0 - 100 in a 3s interval using CSS transition property. When I change this property in Chrome Developer tools, it grows nicely from 0-100 along the duration of the 3 seconds. However, if I apply the style from the component's ngOnInit(), it's instant. Am I doing something wrong?
EDIT: I did solve the problem by myself, however an answer which also explains why it works would be great.
Component.ts:
#Component({
selector: 'notFound',
templateUrl: 'app/notFound.component/notFound.component.html',
directives: [ROUTER_DIRECTIVES]
})
export class NotFoundComponent {
ngOnInit() {
(<HTMLElement>document.querySelector('.determinate')).style.width = "100%";
}
}
Component.html:
<div class="wrapper">
<i class="material-icons error">error_outline</i>
<div class="not-found-text"> No such page 'round here.</div>
<a [routerLink]="['Menu']" class="waves-effect waves-light btn blue">
<i class="material-icons">home</i>
<!--home-->
</a>
<div class="progress">
<div class="determinate"></div>
</div>
</div>
<style>
.progress {
margin-top: 30px;
background: white;
}
.determinate {
width: 0%;
background: #2196F3;
transition: width 3s ease-in-out;
}
</style>
I solved it by wrapping the call in a 0ms setTimeout. What a suprise.
ngOnInit() {
setTimeout(function () {
(<HTMLElement>document.querySelector('.determinate')).style.width = "100%";
}, 0);
}