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].
|
- Improved reconnect handling if the server was flushed [#3297].
|
||||||
- Highlight list entries in a light blue, if a related object is projected (e.g.
|
- Highlight list entries in a light blue, if a related object is projected (e.g.
|
||||||
a list of speakers of a motion) [#3301]
|
a list of speakers of a motion) [#3301]
|
||||||
|
- Select the projector resolution with a slider and an aspect ratio [#3311].
|
||||||
|
|
||||||
Mediafiles:
|
Mediafiles:
|
||||||
- Fixed reloading of PDF on page change [#3274].
|
- 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-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-ui-tree <https://github.com/angular-ui-tree/angular-ui-tree>`_, License: MIT
|
||||||
* `angular-xeditable <https://github.com/vitalets/angular-xeditable>`_, 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
|
* `api-check <https://github.com/kentcdodds/api-check>`_, License: MIT
|
||||||
* `bootstrap <http://getbootstrap.com>`_, License: MIT
|
* `bootstrap <http://getbootstrap.com>`_, License: MIT
|
||||||
* `bootstrap-ui-datetime-picker <https://github.com/Gillardo/bootstrap-ui-datetime-picker>`_, 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-router": "~0.3.1",
|
||||||
"angular-ui-tree": "~2.22.0",
|
"angular-ui-tree": "~2.22.0",
|
||||||
"angular-xeditable": "~0.5.0",
|
"angular-xeditable": "~0.5.0",
|
||||||
|
"angularjs-slider": "~6.2.2",
|
||||||
"bootstrap-css-only": "~3.3.6",
|
"bootstrap-css-only": "~3.3.6",
|
||||||
"bootstrap-ui-datetime-picker": "~2.4.0",
|
"bootstrap-ui-datetime-picker": "~2.4.0",
|
||||||
"ckeditor": "4.6.1",
|
"ckeditor": "4.6.1",
|
||||||
|
@ -1444,6 +1444,31 @@ img {
|
|||||||
font-size: 85%;
|
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: override ngdialog-theme-default */
|
||||||
|
|
||||||
.ngdialog.ngdialog-theme-default {
|
.ngdialog.ngdialog-theme-default {
|
||||||
|
@ -20,6 +20,7 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
'ckeditor',
|
'ckeditor',
|
||||||
'luegg.directives',
|
'luegg.directives',
|
||||||
'xeditable',
|
'xeditable',
|
||||||
|
'rzModule',
|
||||||
])
|
])
|
||||||
|
|
||||||
// Can be used to find out if the projector or the side is used
|
// 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) {
|
ProjectorMessage, ngDialog) {
|
||||||
ProjectionDefault.bindAll({}, $scope, 'projectiondefaults');
|
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
|
// watch for changes in projector_broadcast
|
||||||
// and projector_currentListOfSpeakers_reference
|
// and projector_currentListOfSpeakers_reference
|
||||||
var last_broadcast, last_clos;
|
var last_broadcast, last_clos;
|
||||||
@ -1448,8 +1463,9 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
|
|
||||||
// watch for changes in Projector, and recalc scale and iframeHeight
|
// watch for changes in Projector, and recalc scale and iframeHeight
|
||||||
var first_watch = true;
|
var first_watch = true;
|
||||||
$scope.resolutions = [];
|
$scope.resolutions = {};
|
||||||
$scope.edit = [];
|
$scope.edit = [];
|
||||||
|
$scope.sliders = {};
|
||||||
$scope.$watch(function () {
|
$scope.$watch(function () {
|
||||||
return Projector.lastModified();
|
return Projector.lastModified();
|
||||||
}, function () {
|
}, function () {
|
||||||
@ -1463,6 +1479,25 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
height: projector.height
|
height: projector.height
|
||||||
};
|
};
|
||||||
$scope.edit[projector.id] = false;
|
$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) {
|
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
|
// Set list of speakers reference
|
||||||
$scope.setListOfSpeakers = function (projector) {
|
$scope.setListOfSpeakers = function (projector) {
|
||||||
Config.get('projector_currentListOfSpeakers_reference').value = projector.id;
|
Config.get('projector_currentListOfSpeakers_reference').value = projector.id;
|
||||||
@ -1521,14 +1586,18 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
projector.config = projector.elements;
|
projector.config = projector.elements;
|
||||||
Projector.save(projector);
|
Projector.save(projector);
|
||||||
};
|
};
|
||||||
$scope.changeResolution = function (projectorId) {
|
$scope.saveResolution = function (projector) {
|
||||||
$http.post(
|
$http.post(
|
||||||
'/rest/core/projector/' + projectorId + '/set_resolution/',
|
'/rest/core/projector/' + projector.id + '/set_resolution/',
|
||||||
$scope.resolutions[projectorId]
|
$scope.resolutions[projector.id]
|
||||||
).then(function (success) {
|
).then(function (success) {
|
||||||
$scope.resolutions[projectorId].error = null;
|
$scope.resolutions[projector.id].error = null;
|
||||||
}, function (error) {
|
}, 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 }}:
|
{{ projector.id }}:
|
||||||
<strong>{{ projector.name | translate }}</strong>
|
<strong>{{ projector.name | translate }}</strong>
|
||||||
</a>
|
</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>
|
||||||
|
|
||||||
<div ng-show="edit[projector.id]" style="margin-bottom: -20px;">
|
<div ng-show="edit[projector.id]" style="margin-bottom: -20px;">
|
||||||
<div>
|
<div>
|
||||||
<div class="dropdown" uib-dropdown>
|
<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>
|
<translate>Projection defaults</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="menuProjector{{ pr.id }}">
|
<ul class="dropdown-menu" uib-dropdown-menu aria-labelledby="menuProjector{{ projector.id }}">
|
||||||
<li ng-repeat="projectiondefault in projectiondefaults | orderBy:'id'"
|
<li ng-repeat="projectiondefault in projectiondefaults | orderBy:'id'">
|
||||||
ng-click="setProjectionDefault(projector, projectiondefault)">
|
<a href ng-click="setProjectionDefault(projector, projectiondefault)">
|
||||||
<i class="fa fa-check" ng-if="projectiondefault.projector_id === projector.id"></i>
|
<i class="fa fa-check" ng-if="projectiondefault.projector_id === projector.id"></i>
|
||||||
{{ projectiondefault.display_name | translate }}
|
{{ projectiondefault.display_name | translate }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -82,19 +83,30 @@
|
|||||||
<div>
|
<div>
|
||||||
<label for="resolution{{ projector.id }}" class="control-label"><translate>Resolution</translate>:</label>
|
<label for="resolution{{ projector.id }}" class="control-label"><translate>Resolution</translate>:</label>
|
||||||
<div id="resolution{{ projector.id }}">
|
<div id="resolution{{ projector.id }}">
|
||||||
<input ng-model="resolutions[projector.id].width"
|
<div>
|
||||||
ng-model-option="{debounce: 2000}"
|
<span>
|
||||||
ng-change="changeResolution(projector.id)"
|
{{ resolutions[projector.id].width }}×{{ resolutions[projector.id].height }}
|
||||||
class="form-control resolution"
|
</span>
|
||||||
id="{{ projector.id }}_width"
|
<div class="dropdown" uib-dropdown>
|
||||||
type="number">
|
<button class="btn btn-default btn-sm" id="aspectRatio{{ projector.id }}" uib-dropdown-toggle>
|
||||||
x
|
<translate>Aspect ratio</translate>: {{ resolutions[projector.id].aspectRatio }}
|
||||||
<input ng-model="resolutions[projector.id].height"
|
<span class="caret"></span>
|
||||||
ng-model-option="{debounce: 2000}"
|
</button>
|
||||||
ng-change="changeResolution(projector.id)"
|
<ul class="dropdown-menu" uib-dropdown-menu aria-labelledby="aspectRatio{{ projector.id }}">
|
||||||
class="form-control resolution"
|
<li ng-repeat="(aspectRatio, value) in aspectRatios track by $index">
|
||||||
id="{{ projector.id }}_height"
|
<a href ng-click="setAspectRatio(projector, aspectRatio); saveResolution(projector);">
|
||||||
type="number">
|
<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>
|
</div>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
{{ resolutions[projector.id].error }}
|
{{ 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):
|
if not isinstance(request.data['width'], int) or not isinstance(request.data['height'], int):
|
||||||
raise ValidationError({'detail': 'Data has to be integers.'})
|
raise ValidationError({'detail': 'Data has to be integers.'})
|
||||||
if (request.data['width'] < 800 or request.data['width'] > 3840 or
|
if (request.data['width'] < 800 or request.data['width'] > 3840 or
|
||||||
request.data['height'] < 600 or request.data['height'] > 2160):
|
request.data['height'] < 340 or request.data['height'] > 2880):
|
||||||
raise ValidationError({'detail': 'The Resolution have to be between 800x600 and 3840x2160.'})
|
raise ValidationError({'detail': 'The Resolution have to be between 800x340 and 3840x2880.'})
|
||||||
|
|
||||||
projector_instance = self.get_object()
|
projector_instance = self.get_object()
|
||||||
projector_instance.width = request.data['width']
|
projector_instance.width = request.data['width']
|
||||||
|
Loading…
Reference in New Issue
Block a user