"ing cnvs"
Bootstrap 3.0.0 Snippet by irinashuvalova

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> <link href="/css/markupImage.css" /> </head> <body> <div id="app"></div> <template id="areaListItemTemplate"> <li class="areas-list__item" v-bind:class="[ editing ? 'areas-list__item--editing' : 'areas-list__item--view' ]"> <template v-if="editing"> <ui-textbox v-model="title" placeholder="Введите название" class="fluid-input"></ui-textbox> <ui-textbox v-model="url" placeholder="Укажите ссылку" class="fluid-input"></ui-textbox> <ui-colorpicker v-model="color" class="fluid-input"></ui-colorpicker> <div class="btn-group"> <button type="button" class="btn btn-primary" @click="accept">Добавить</button> <button type="button" class="btn btn-secondary" @click="cancel">Отмена</button> </div> </template> <template v-else> <div class="btn-group"> <button type="button" class="btn edit-btn" @click="$emit('edit', area)"></button> <button type="button" class="btn remove-btn" @click="$emit('remove', area)"></button> </div> <span class="areas-list__title">{{ area.title }}</span> </template> </li> </template> <template id="appTemplate"> <div class="wss-imagemarkup"> <div class="wss-imagemarkup__editor image-markup-editor"> <div class="image-markup-editor__image"> <div class="image-markup-editor__container" v-bind:style="containerStyle" @click="appendPoint"> <img v-bind:src="imageUrl" @load.once="imageLoaded" /> <canvas ref="canvas"></canvas> </div> </div> <div class="image-markup-editor__controls"> <h3>Редактировать</h3> <ul class="areas-list"> <li class="areas-list__create-area" v-bind:class="{ 'areas-list__create-area--hidden': activeArea != null }"> <button type="button" class="btn create-btn" @click="createArea">Добавить ссылку</button> </li> <area-list-item v-for="area in areas" v-bind:area="area" v-bind:editing="area === activeArea" @accept="commitAreaChanges" @cancel="discardAreaChanges" @edit="selectArea" @remove="removeArea"> </area-list-item> </ul> <div class="btn-group"> <button type="button" class="btn btn-primary" @click="save">Сохранить</button> <button type="button" class="btn btn-secondary" @click="cancel">Отмена</button> </div> </div> </div> </div> </template> <script src="/plugins/vuejs/vue.min.js"></script> <script src="/plugins/paper/paper-core.min.js"></script> <script src="/plugins/jscolor.js"></script> <script> var DEFAULT_STROKE_COLOR = '#ebfb5b'; var placeholderFeature = 'placeholder' in HTMLInputElement.prototype; function getPoint(e) { var rect = e.target.getBoundingClientRect(); return [e.clientX - rect.left, e.clientY - rect.top]; } Vue.component('ui-colorpicker', { template: '<input type="text" :value="value" @change="update" class="jscolor input"/>', model: { prop: 'value', event: 'change' }, props: ['value'], mounted: function () { jscolor.installByClassName('jscolor'); }, methods: { update: function (e) { var val = e.target.value; if (val[0] !== '#') { val = '#' + val; } this.$emit('change', val); } } }); Vue.component('ui-textbox', { template: '<input type="text" :value="inputValue" class="input" :class="{\'input--placeholder\': placeholderActive }" :placeholder.once="placeholder" @input="$emit(\'input\', $event.target.value)"/>', model: { prop: 'value', event: 'input' }, props: ['value', 'placeholder'], data: function () { return { inputValue: null } }, mounted: function () { this.inputValue = this.value; if (!placeholderFeature) { this.inputValue = this.inputValue || this.placeholder; this.$el.addEventListener('focus', (function () { if (this.inputValue != this.value) { this.inputValue = this.value } }).bind(this)); this.$el.addEventListener('blur', (function () { if (!this.value) { this.inputValue = this.placeholder } }).bind(this)); this.$watch('value', (function (newValue) { if (!!newValue) { this.inputValue = newValue; } else { this.inputValue = this.placeholder; } }).bind(this)); } }, computed: { placeholderActive: function () { return !window.placeholderFeature && this.inputValue === this.placeholder; } } }) Vue.component('area-list-item', { template: '#areaListItemTemplate', props: ['area', 'editing'], mounted: function () { this.createPath(); }, destroyed: function () { if (this.path) { this.path.remove(); } }, data: function () { var color = this.area.color || DEFAULT_STROKE_COLOR; return { url: this.area.url, title: this.area.title, color: color, path: null } }, methods: { accept: function () { if (!this.url || !this.title) { alert('Необходимо указать название и ссылку'); return; } this.area.url = this.url; this.area.title = this.title; this.area.color = this.color; this.$emit('accept', this.area); }, cancel: function () { if (this.id) { this.url = this.area.url; this.title = this.area.title; this.color = this.area.color; this.$emit('cancel', this.area); } else { this.$emit('remove', this.area); } }, createPath: function () { if (!paper.project) { setTimeout(this.createPath, 100); return; } this.path = new paper.Path({ segments: this.area.points || [], selected: this.editing, fillColor: new paper.Color(255, 255, 255, 0.5), strokeWidth: 2, strokeColor: this.color }); } }, watch: { 'editing': function (newVal) { if (!this.path) return; if (newVal) { this.path.selected = true; } else { this.path.selected = false; } }, 'area.points': function (newValue) { if (this.path && newValue && newValue.length > 0) { var point = newValue[newValue.length - 1]; this.path.add(new paper.Point(point[0], point[1])); } }, 'area.color': function (newValue) { if (this.path) { this.path.strokeColor = newValue; } } } }); function create(data) { data.image = data.image || {}; var app = new Vue({ el: '#app', template: '#appTemplate', data: { uuid: data.uuid, imageUrl: data.image.url || null, imageWidth: 0, imageHeight: 0, areas: data.areas || [], activeArea: null }, methods: { imageLoaded: function (event) { var image = event.target; this.imageWidth = image.width; this.imageHeight = image.height; this.$nextTick(this.setupCanvas); }, setupCanvas: function () { paper.setup(this.$refs.canvas); }, createArea: function () { if (this.activeArea === null) { var newArea = { id: 0, url: '', title: '', points: [] }; this.areas.push(newArea); this.selectArea(newArea); } }, commitAreaChanges: function (area) { if (!area.id) { area.id = this.areas.reduce(function (max, current) { return Math.max(max, current.id); }, 0) + 1; } this.selectArea(); }, discardAreaChanges: function (area) { if (area.id) { this.removeArea(area.id); } }, selectArea: function (area) { this.activeArea = area || null; }, removeArea: function (area) { if (area === this.activeArea) { this.selectArea(null); } var index = this.areas.indexOf(area); this.areas.splice(index, 1); }, appendPoint: function (event) { if (!this.activeArea) return; if (!this.activeArea.points) { Vue.set(this.activeArea, 'points', []); } this.activeArea.points.push(getPoint(event)); }, save: function () { var updated = { uuid: this.uuid, image: { url: this.imageUrl, width: this.imageWidth, height: this.imageHeight }, areas: JSON.parse(JSON.stringify(this.areas)) }; window.parent.wssc.ribbon.imageMarkupUpdated(updated); }, cancel: function () { window.parent.wssc.ribbon.closeImageMarkupEditor(); } }, computed: { containerStyle: function () { return { width: this.imageWidth > 0 ? this.imageWidth + 'px' : 'auto', height: this.imageHeight > 0 ? this.imageHeight + 'px' : 'auto', } } } }); } </script> </body> </html>

Related: See More


Questions / Comments: