Merge pull request #3311 from FinnStutzenstein/projector-size
Projectorsize selection with slider
This commit is contained in:
commit
574d815397
@ -52,6 +52,7 @@ Core:
|
||||
- Improved reconnect handling if the server was flushed [#3297].
|
||||
- Highlight list entries in a light blue, if a related object is projected (e.g.
|
||||
a list of speakers of a motion) [#3301]
|
||||
- Select the projector resolution with a slider and an aspect ratio [#3311].
|
||||
|
||||
Mediafiles:
|
||||
- Fixed reloading of PDF on page change [#3274].
|
||||
|
@ -185,6 +185,7 @@ OpenSlides uses the following projects or parts of them:
|
||||
* `angular-ui-router <http://angular-ui.github.io/ui-router/>`_, License: MIT
|
||||
* `angular-ui-tree <https://github.com/angular-ui-tree/angular-ui-tree>`_, License: MIT
|
||||
* `angular-xeditable <https://github.com/vitalets/angular-xeditable>`_, License: MIT
|
||||
* `angularjs-slider <https://github.com/angular-slider/angularjs-slider>`_, License: MIT
|
||||
* `api-check <https://github.com/kentcdodds/api-check>`_, License: MIT
|
||||
* `bootstrap <http://getbootstrap.com>`_, License: MIT
|
||||
* `bootstrap-ui-datetime-picker <https://github.com/Gillardo/bootstrap-ui-datetime-picker>`_, License: MIT
|
||||
|
@ -20,6 +20,7 @@
|
||||
"angular-ui-router": "~0.3.1",
|
||||
"angular-ui-tree": "~2.22.0",
|
||||
"angular-xeditable": "~0.5.0",
|
||||
"angularjs-slider": "~6.2.2",
|
||||
"bootstrap-css-only": "~3.3.6",
|
||||
"bootstrap-ui-datetime-picker": "~2.4.0",
|
||||
"ckeditor": "4.6.1",
|
||||
|
@ -1444,6 +1444,31 @@ img {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
/* Custom OpenSlides slider classes */
|
||||
.os-slider {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.os-slider.rzslider .rz-bar {
|
||||
background: #317796;
|
||||
opacity: 0.3;
|
||||
height: 2px;
|
||||
}
|
||||
.os-slider.rzslider .rz-selection {
|
||||
background: #317796;
|
||||
}
|
||||
.os-slider.rzslider .rz-pointer {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
top: -7px;
|
||||
bottom: 0;
|
||||
background-color: #317796;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.os-slider.rzslider .rz-pointer:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ngDialog: override ngdialog-theme-default */
|
||||
|
||||
.ngdialog.ngdialog-theme-default {
|
||||
|
@ -20,6 +20,7 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
'ckeditor',
|
||||
'luegg.directives',
|
||||
'xeditable',
|
||||
'rzModule',
|
||||
])
|
||||
|
||||
// Can be used to find out if the projector or the side is used
|
||||
@ -1428,6 +1429,20 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
ProjectorMessage, ngDialog) {
|
||||
ProjectionDefault.bindAll({}, $scope, 'projectiondefaults');
|
||||
|
||||
/* Info on resolution calculating:
|
||||
* Internally the resolution is saved as (width, height) but the user has
|
||||
* an aspect ratio to choose and a width from 800 to 3840 (4K).*/
|
||||
$scope.aspectRatios = {
|
||||
'4:3': 4/3,
|
||||
'16:9': 16/9,
|
||||
'16:10': 16/10,
|
||||
};
|
||||
// when converting (x,y) -> (ratio, percentage) round issues may occur
|
||||
// (e.g. 800/600 != 4/3 with internal calculation issues). With this environment
|
||||
// is tested, if the calculated value is in the following interval:
|
||||
// [expected-environment; expected+environment]
|
||||
var RATIO_ENVIRONMENT = 0.05;
|
||||
|
||||
// watch for changes in projector_broadcast
|
||||
// and projector_currentListOfSpeakers_reference
|
||||
var last_broadcast, last_clos;
|
||||
@ -1448,8 +1463,9 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
|
||||
// watch for changes in Projector, and recalc scale and iframeHeight
|
||||
var first_watch = true;
|
||||
$scope.resolutions = [];
|
||||
$scope.resolutions = {};
|
||||
$scope.edit = [];
|
||||
$scope.sliders = {};
|
||||
$scope.$watch(function () {
|
||||
return Projector.lastModified();
|
||||
}, function () {
|
||||
@ -1463,6 +1479,25 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
height: projector.height
|
||||
};
|
||||
$scope.edit[projector.id] = false;
|
||||
$scope.sliders[projector.id] = {
|
||||
value: projector.width,
|
||||
options: {
|
||||
id: projector.id,
|
||||
floor: 800,
|
||||
ceil: 3840,
|
||||
translate: function (value) {
|
||||
return value + 'px';
|
||||
},
|
||||
onChange: function (v) {
|
||||
$scope.calcResolution(projector);
|
||||
},
|
||||
onEnd: function (v) {
|
||||
$scope.saveResolution(projector);
|
||||
},
|
||||
hideLimitLabels: true,
|
||||
},
|
||||
};
|
||||
$scope.setAspectRatio(projector, $scope.getAspectRatio(projector));
|
||||
}
|
||||
});
|
||||
if ($scope.projectors.length) {
|
||||
@ -1470,6 +1505,36 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
}
|
||||
});
|
||||
|
||||
$scope.getAspectRatio = function (projector) {
|
||||
var ratio = projector.width/projector.height;
|
||||
var foundRatio = _.findKey($scope.aspectRatios, function (value) {
|
||||
return value >= (ratio-RATIO_ENVIRONMENT) && value <= (ratio+RATIO_ENVIRONMENT);
|
||||
});
|
||||
if (foundRatio === undefined) {
|
||||
return _.keys($scope.aspectRatios)[0];
|
||||
} else {
|
||||
return foundRatio;
|
||||
}
|
||||
};
|
||||
$scope.setAspectRatio = function (projector, aspectRatio) {
|
||||
$scope.resolutions[projector.id].aspectRatio = aspectRatio;
|
||||
$scope.resolutions[projector.id].aspectRatioNumber = $scope.aspectRatios[aspectRatio];
|
||||
$scope.calcResolution(projector);
|
||||
};
|
||||
$scope.calcResolution = function (projector) {
|
||||
var ratio = $scope.resolutions[projector.id].aspectRatioNumber;
|
||||
var width = $scope.sliders[projector.id].value;
|
||||
$scope.resolutions[projector.id].width = width;
|
||||
$scope.resolutions[projector.id].height = Math.round(width/ratio);
|
||||
};
|
||||
|
||||
$scope.toggleEditMenu = function (projectorId) {
|
||||
$scope.edit[projectorId] = !$scope.edit[projectorId];
|
||||
$timeout(function () {
|
||||
$scope.$broadcast('rzSliderForceRender');
|
||||
});
|
||||
};
|
||||
|
||||
// Set list of speakers reference
|
||||
$scope.setListOfSpeakers = function (projector) {
|
||||
Config.get('projector_currentListOfSpeakers_reference').value = projector.id;
|
||||
@ -1521,14 +1586,18 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
projector.config = projector.elements;
|
||||
Projector.save(projector);
|
||||
};
|
||||
$scope.changeResolution = function (projectorId) {
|
||||
$scope.saveResolution = function (projector) {
|
||||
$http.post(
|
||||
'/rest/core/projector/' + projectorId + '/set_resolution/',
|
||||
$scope.resolutions[projectorId]
|
||||
'/rest/core/projector/' + projector.id + '/set_resolution/',
|
||||
$scope.resolutions[projector.id]
|
||||
).then(function (success) {
|
||||
$scope.resolutions[projectorId].error = null;
|
||||
$scope.resolutions[projector.id].error = null;
|
||||
}, function (error) {
|
||||
$scope.resolutions[projectorId].error = error.data.detail;
|
||||
if (error.data) {
|
||||
$scope.resolutions[projector.id].error = error.data.detail;
|
||||
} else {
|
||||
$scope.resolutions[projector.id].error = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -45,21 +45,22 @@
|
||||
{{ projector.id }}:
|
||||
<strong>{{ projector.name | translate }}</strong>
|
||||
</a>
|
||||
<a href="" class="pull-right" ng-click="edit[projector.id] = !edit[projector.id]"><i class="fa" ng-class="edit[projector.id] ? 'fa-times' : 'fa-pencil'"></i></a>
|
||||
<a href="" class="pull-right" ng-click="toggleEditMenu(projector.id)"><i class="fa" ng-class="edit[projector.id] ? 'fa-times' : 'fa-pencil'"></i></a>
|
||||
</div>
|
||||
|
||||
<div ng-show="edit[projector.id]" style="margin-bottom: -20px;">
|
||||
<div>
|
||||
<div class="dropdown" uib-dropdown>
|
||||
<button class="btn btn-default btn-sm" id="menuProjector{{ pr.id }}" uib-dropdown-toggle>
|
||||
<button class="btn btn-default btn-sm" id="menuProjector{{ projector.id }}" uib-dropdown-toggle>
|
||||
<translate>Projection defaults</translate>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="menuProjector{{ pr.id }}">
|
||||
<li ng-repeat="projectiondefault in projectiondefaults | orderBy:'id'"
|
||||
ng-click="setProjectionDefault(projector, projectiondefault)">
|
||||
<i class="fa fa-check" ng-if="projectiondefault.projector_id === projector.id"></i>
|
||||
{{ projectiondefault.display_name | translate }}
|
||||
<ul class="dropdown-menu" uib-dropdown-menu aria-labelledby="menuProjector{{ projector.id }}">
|
||||
<li ng-repeat="projectiondefault in projectiondefaults | orderBy:'id'">
|
||||
<a href ng-click="setProjectionDefault(projector, projectiondefault)">
|
||||
<i class="fa fa-check" ng-if="projectiondefault.projector_id === projector.id"></i>
|
||||
{{ projectiondefault.display_name | translate }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -82,19 +83,30 @@
|
||||
<div>
|
||||
<label for="resolution{{ projector.id }}" class="control-label"><translate>Resolution</translate>:</label>
|
||||
<div id="resolution{{ projector.id }}">
|
||||
<input ng-model="resolutions[projector.id].width"
|
||||
ng-model-option="{debounce: 2000}"
|
||||
ng-change="changeResolution(projector.id)"
|
||||
class="form-control resolution"
|
||||
id="{{ projector.id }}_width"
|
||||
type="number">
|
||||
x
|
||||
<input ng-model="resolutions[projector.id].height"
|
||||
ng-model-option="{debounce: 2000}"
|
||||
ng-change="changeResolution(projector.id)"
|
||||
class="form-control resolution"
|
||||
id="{{ projector.id }}_height"
|
||||
type="number">
|
||||
<div>
|
||||
<span>
|
||||
{{ resolutions[projector.id].width }}×{{ resolutions[projector.id].height }}
|
||||
</span>
|
||||
<div class="dropdown" uib-dropdown>
|
||||
<button class="btn btn-default btn-sm" id="aspectRatio{{ projector.id }}" uib-dropdown-toggle>
|
||||
<translate>Aspect ratio</translate>: {{ resolutions[projector.id].aspectRatio }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu aria-labelledby="aspectRatio{{ projector.id }}">
|
||||
<li ng-repeat="(aspectRatio, value) in aspectRatios track by $index">
|
||||
<a href ng-click="setAspectRatio(projector, aspectRatio); saveResolution(projector);">
|
||||
<i class="fa fa-check" ng-if="aspectRatio === resolutions[projector.id].aspectRatio"></i>
|
||||
{{ aspectRatio }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<rzslider class="os-slider"
|
||||
rz-slider-model="sliders[projector.id].value"
|
||||
rz-slider-options="sliders[projector.id].options"></rzslider>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">
|
||||
{{ resolutions[projector.id].error }}
|
||||
|
@ -404,8 +404,8 @@ class ProjectorViewSet(ModelViewSet):
|
||||
if not isinstance(request.data['width'], int) or not isinstance(request.data['height'], int):
|
||||
raise ValidationError({'detail': 'Data has to be integers.'})
|
||||
if (request.data['width'] < 800 or request.data['width'] > 3840 or
|
||||
request.data['height'] < 600 or request.data['height'] > 2160):
|
||||
raise ValidationError({'detail': 'The Resolution have to be between 800x600 and 3840x2160.'})
|
||||
request.data['height'] < 340 or request.data['height'] > 2880):
|
||||
raise ValidationError({'detail': 'The Resolution have to be between 800x340 and 3840x2880.'})
|
||||
|
||||
projector_instance = self.get_object()
|
||||
projector_instance.width = request.data['width']
|
||||
|
Loading…
Reference in New Issue
Block a user