/*
* @title open2chOekakiEX
* @description おーぷん2ちゃんお絵かき機能拡張ブックマークレット
* @private
*/
/*
【更新履歴】
Ver1.0.0 2014/03/29 文字入力機能追加
Ver1.1.0 2014/03/29 お絵かき機能ツールメニュー内に文字入力機能を追加 文字サイズ指定追加
Ver1.2.0 2014/03/30 フォント指定、修飾指定追加
Ver1.3.0 2014/03/30 線描画と文字入力のUNDO/REDO機能追加 イタリックが効かないバグ修正
Ver2.0.0 2014/03/31 塗りつぶし機能追加
Ver2.1.0 2014/03/31 塗りつぶし機能にUNDO/REDO機能追加
Ver2.1.1 2014/03/31 IE、Chromeで塗りつぶしが効かないバグ修正
Ver2.2.0 2014/04/01 背景色以外の色も塗りつぶせるように修正
Ver2.3.0 2014/04/01 透明度を指定して塗りつぶせるように修正
Ver2.4.0 2014/04/02 文字入力でフォントの直接指定&改行入力&縦書出力に対応
Ver3.0.0 2014/04/05 お絵かき再生機能追加
Ver3.1.0 2014/04/06 お絵かき再生機能のエクスポート方式をテキストから画像埋め込みに変更
Ver3.2.0 2014/04/10 お絵かき再生機能で塗りつぶしと消しゴムが再生できるように修正 線を引くときにちらつくバグを修正
Ver4.0.0 2014/04/19 レイヤ機能追加
Ver4.1.0 2014/04/20 レイヤの表示/非表示切替機能追加 最前面のレイヤしか投稿できないバグ修正 レイヤの移動に関するバグ修正 コラボするとレイヤの重なりがおかしくなるバグ修正
Ver4.1.1 2014/04/24 IE10未満で起動できないバグを修正
Ver4.1.2 2014/04/28 IEでプレビューが正常に表示できないバグを修正
Ver4.2.0 2014/04/29 レイヤ機能をデフォルトではオフに変更 レイヤ機能オン時の性能向上
Ver4.2.1 2014/04/29 絵が投稿できないバグを修正
Ver4.3.0 2014/04/29 線の太さ、文字の大きさを追加
Ver5.0.0 2014/05/01 図形描画機能追加 レイヤ機能をデフォルトでオンに変更 「進」ボタン追加
Ver5.1.0 2014/05/03 文字入力後に文字位置を移動できる機能を追加 マニュアル表示追加
Ver5.1.1 2014/05/03 一部文字が投稿できないバグを修正
*/
var PREVIEW_SIZE = 0.2;
var MARGIN = 5;
var canvas = $('#sketch').sketch();
var drawRedo = [];
var layers = [];
var layerOnFlag = true;
//var layerOnFlag = false;
initDrawTool();
initLayerTool();
$('#layerTool').next().css('background', '#ddd');
$('#layerTool').next().children().html("\
<FONT size=+1><B>【主な機能】</B></FONT><BR><BR>\
・<B>線描画機能</B><BR>\
- 選べる線の太さを拡張<BR>\
<BR>\
・<B>文字入力機能</B><BR>\
- ツールメニューの[A]を選択して、文字を書きたい場所をクリック<BR>\
- 色、サイズ、フォント、装飾をツールメニューから選択可能<BR>\
- 先頭に『!』と入力すると縦書で出力(フォント指定よりも前に入力)<BR>\
- 先頭に『[フォント名]』と入力すると指定したフォントで文字を出力<BR>\
- 文字列中に『\\n』を入れるとそこで改行<BR>\
<BR>\
・<B>塗りつぶし機能</B><BR>\
- ツールメニューのバケツマークを選択して、塗りつぶしたい箇所をクリック<BR>\
- 色、透明度を選択可能<BR>\
<BR>\
・<B>図形描画機能</B><BR>\
- ツールメニューの「図形」プルダウンから図形を選択<BR>\
- 直線、四角形、円を描画可能<BR>\
<BR>\
・<B>お絵かき再生機能(現在停止中)</B><BR>\
<S>- 絵を描いた後「出力」ボタンを押すと絵の情報が画像内に埋め込まれる</S><BR>\
<S>- 情報が埋め込まれた絵をコラボして「再生」ボタンを押すと再生</S><BR>\
<BR>\
・<B>レイヤ機能</B><BR>\
- キャンバス下の「機能ON」をクリックすることでレイヤ機能が有効化<BR>\
- 「追加」をクリックでレイヤを追加<BR>\
- プレビューをクリックでレイヤの選択<BR>\
- 「表示」をクリックで選択したレイヤの表示/非表示切替<BR>\
- 「←」「→」で選択したレイヤの位置(前面、背面)を入れ替え<BR>\
<BR>\
・<B>ショートカットキー</B><BR>\
- [ctrl + ←]:UNDO <BR>\
- [ctrl + →]:REDO");
function initDrawTool(){
$('#_canvas').attr('style', 'position: relative');
var penSizeSelect = $('#psize');
penSizeSelect.children().remove();
var penSize = [0.5, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 100];
for(var i in penSize){
$('<option>', {
value: penSize[i],
text: penSize[i],
selected: (i==2)?true:false
}).appendTo(penSizeSelect);
}
var fillInput = $('<input>', {
id: 'fill',
type: 'radio',
name: 'pmode'
});
var fillLabel = $('<label>', {
for: 'fill'
});
var fillImg = $('<img>', {
id: 'fillImg',
src: 'http://image.open2ch.net/image/oekaki/nuri.png',
}).appendTo(fillLabel);
var mojiInput = $('<input>', {
id:'moji',
type:'radio',
name:'pmode'
});
var mojiText = $('<b>',{
text:'[A]:'
});
var mojiLabel = $('<label>', {
for:'moji'
});
mojiText.appendTo(mojiLabel);
var size = [4, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 100];
var mojiSelect = $('<select>', {
id: 'mojiSize'
});
for(var i in size){
$('<option>', {
value: size[i],
text: size[i],
selected: (i==7)?true:false
}).appendTo(mojiSelect);
}
var font = ['ゴシック','明朝','筆記体','装飾','等幅'];
var fontSelect = $('<select>', {
id: 'mojiFont'
});
for(var i in font){
$('<option>', {
value: i,
text: font[i],
}).appendTo(fontSelect);
}
var boldText = $('<b>', {
text: ' B:'
});
var boldCheck = $('<input>', {
id: 'mojiBold',
type: 'checkbox',
value: 'bold'
});
var italicText = $('<i>', {
text: ' I:'
});
var italicCheck = $('<input>', {
id: 'mojiItalic',
type: 'checkbox',
value: 'italic'
});
var br = $('<br>');
var figureInput = $('<input>', {
id: 'figure',
type: 'radio',
name: 'pmode'
});
var figureLabel = $('<label>', {
for: 'figure'
});
var figureText = $('<b>', {
text: ' 図形:'
});
figureText.appendTo(figureLabel);
var figure = ['-','□','■','○','●'];
var figureSelect = $('<select>', {
id: 'figureType'
});
for(var i in figure){
$('<option>', {
value: i,
text: figure[i],
}).appendTo(figureSelect);
}
var goButton = $('<input>', {
type: 'button',
value: '進',
id: 'goButton',
click: function(){
changeAction(drawRedo, canvas.actions);
canvas.redraw();
}
});
$('#backButton')
.before(fillInput)
.before(fillLabel)
.before(mojiInput)
.before(mojiLabel)
.before(mojiSelect)
.before(fontSelect)
.before(boldText)
.before(boldCheck)
.before(italicText)
.before(italicCheck)
.before(br)
.before(figureInput)
.before(figureLabel)
.before(figureSelect)
.after(goButton);
var mojiA = $('<a>', {
href: '#sketch',
'data-tool': 'moji'
});
var fillA = $('<a>', {
href: '#sketch',
'data-tool': 'fill'
});
var figureA = $('<a>', {
href: '#sketch',
'data-tool': 'figure'
});
mojiInput.click(function(){$('[data-tool=moji]').click()});
fillInput.click(function(){$('[data-tool=fill]').click()});
figureInput.click(function(){$('[data-tool=figure]').click()});
$('.tools').after(fillA).after(mojiA).after(figureA);
$('[data-tool]').click(function(){moveText();});
var exportButton = $('<input>', {
id: 'exportButton',
type: 'button',
value: '出力'
});
var importButton = $('<input>', {
id: 'importButton',
type: 'button',
value: '再生'
});
//$('#saveButton').after(importButton).after(exportButton);
importButton.click(function(){
playback(stringToAction(colorToActionString()), 10);
});
exportButton.click(function(){
actionStringToColor(actionToString());
});
var tmpCanvas = $('<canvas>').attr({
id: 'tmpCanvas',
width: canvas.el.width,
height: canvas.el.height,
style: 'position:absolute; z-index:-1'
});
$('#sketch').before(tmpCanvas);
var layerTool = $('<div>', {
id: 'layerTool',
align: 'left',
style: 'background:#ccc;padding:2px;font-size:9pt'
});
var layerText = $('<b>', {
text: '[レイヤ]:'
});
var layerOnButton = $('<input>', {
id: 'layerOnButton',
type: 'button',
value: '機能ON',
click: function(){
layerOnFlag = true;
initLayerTool();
layerOnButton.remove();
}
});
// layerTool.append(layerText).append(layerOnButton);
var mergeLayerButton = $('<input>', {
id: 'mergeLayerButton',
type: 'button',
value: '結合',
click: function(){mergeLayer()}
});
$('#_canvas').after(layerTool);
// layerTool.append(mergeLayerButton);
}
function initLayerTool(){
var layerTool = $('#layerTool');
var addLayerButton = $('<input>', {
id: 'addLayerButton',
type: 'button',
value: '追加',
click: function(){addLayer()}
});
var displayButton= $('<input>', {
id: 'displayButton',
type: 'button',
value: '表示',
click: function(){changeDisplay()}
});
var changeLayerLeftButton= $('<input>', {
id: 'changeLayerLeftButton',
type: 'button',
value: '←',
click: function(){changeLayer(canvas.layerNum-1)}
});
var changeLayerRightButton = $('<input>', {
id: 'changeLayerRightButton',
type: 'button',
value: '→',
click: function(){changeLayer(canvas.layerNum+1)}
});
var mergeLayerButton = $('<input>', {
id: 'mergeLayerButton',
type: 'button',
value: '結合',
click: function(){mergeLayer()}
});
var previewBox = $('<div>', {
id: 'previewBox',
align: 'left'
});
layerTool
.append(addLayerButton)
.append(displayButton)
.append(changeLayerLeftButton)
.append(changeLayerRightButton)
// .append(mergeLayerButton)
.append(previewBox);
initLayer();
}
function initLayer(){
createLayer();
layers.push({
actions:[]
});
$('#layerCanvas0')[0].style.backgroundImage = 'url(http://open2ch.net/image/oekaki/background.png)';
sketch.style.backgroundImage='none';
createLayer();
createPreview();
layers.push({
canvas:$('#layerCanvas1')[0],
context:$('#layerCanvas1')[0].getContext('2d'),
// bgcolor:canvas.bgcolor,
bgcolor:'rgba(0, 0, 0, 0)',
baseImageURL:canvas.baseImageURL,
actions:canvas.actions
});
canvas.layerNum = 1;
canvas.actions = [];
canvas.bgcolor = 'rgba(0, 0, 0, 0)';
canvas.baseImageURL = '';
canvas.baseImageCache = '';
canvas.redraw();
canvas.el = layers[1].canvas;
canvas.baseImageURL = layers[1].baseImageURL;
canvas.baseImageCache = '';
canvas.actions = layers[1].actions;
updatePreview();
selectLayer(canvas.layerNum);
}
function createLayer(){
var layerCanvas = $('<canvas>').attr({
id: 'layerCanvas' + layers.length,
width: canvas.el.width,
height: canvas.el.height,
style: 'position:absolute; z-index:' + (layers.length-100)
});
$('#sketch').before(layerCanvas);
}
function createPreview(){
var preview = $('<canvas>').attr({
id: 'preview' + (layers.length),
width: canvas.el.width,
height: canvas.el.height,
value: layers.length,
style: 'border:1pt solid #999; background-image:url(http://open2ch.net/image/oekaki/background.png); width:' + canvas.el.width * PREVIEW_SIZE + '; height:' + canvas.el.height * PREVIEW_SIZE,
});
preview.click(function(){selectLayer(preview[0].value)});
preview[0].displayed = true;
$('#previewBox').append(preview);
}
function selectLayer(newLayerNum ){
var oldLayerNum = canvas.layerNum;
$('canvas[id^=preview]').each(function(i){
if((i+1) == newLayerNum){
if(this.displayed){
$(this).css('border', '2pt solid #D33');
}else{
$(this).css('border', '2pt solid #DAA');
}
this.selected = true;
}else{
if(this.displayed){
$(this).css('border', '2pt solid #777');
}else{
$(this).css('border', '2pt solid #BBB');
}
this.selected = false;
}
});
canvas.layerNum = newLayerNum;
layers[oldLayerNum].actions = canvas.actions;
layers[oldLayerNum].bgcolor = canvas.bgcolor;
// layers[oldLayerNum].baseImageURL = canvas.baseImageURL;
canvas.el = layers[newLayerNum].canvas;
canvas.bgcolor = layers[newLayerNum].bgcolor;
canvas.baseImageURL = layers[newLayerNum].baseImageURL;
canvas.baseImageCache = '';
canvas.actions = layers[newLayerNum].actions;
canvas.redraw();
// updatePreview();
}
function updatePreview(){
var preview = $('#preview' + canvas.layerNum)[0];
var context = preview.getContext('2d');
var imageData = canvas.context.getImageData(0, 0, canvas.el.width, canvas.el.height);
context.putImageData(imageData, 0, 0);
}
function addLayer(){
var oldLayerNum = canvas.layerNum;
createLayer();
createPreview();
layers.push({
canvas:$('#layerCanvas' + (layers.length))[0],
context:$('#layerCanvas' + (layers.length))[0].getContext('2d'),
bgcolor:'rgba(0, 0, 0, 0)',
actions:[]
});
var newLayerNum = layers.length-1;
canvas.layerNum = newLayerNum;
layers[oldLayerNum].actions = canvas.actions;
canvas.el = layers[newLayerNum].canvas;
canvas.actions = layers[newLayerNum].actions;
canvas.redraw();
updatePreview();
selectLayer(newLayerNum);
}
function changeLayer(newLayerNum){
if(newLayerNum <= 0 || newLayerNum > layers.length-1){return}
var oldLayerNum = canvas.layerNum;
var tmpZIndex = layers[oldLayerNum].canvas.style.zIndex;
layers[oldLayerNum].canvas.style.zIndex = layers[newLayerNum].canvas.style.zIndex;
layers[newLayerNum].canvas.style.zIndex = tmpZIndex;
var tmpLayer = layers[oldLayerNum];
layers[oldLayerNum] = layers[newLayerNum];
layers[newLayerNum] = tmpLayer;
canvas.actions = layers[oldLayerNum].actions;
var oldCtx = $('#preview' + oldLayerNum)[0].getContext('2d');
var newCtx = $('#preview' + newLayerNum)[0].getContext('2d');
var oldImageData = oldCtx.getImageData(0, 0, canvas.el.width, canvas.el.height);
var newImageData = newCtx.getImageData(0, 0, canvas.el.width, canvas.el.height);
oldCtx.putImageData(newImageData, 0, 0);
newCtx.putImageData(oldImageData, 0, 0);
var tmpPreviewDisplayed = $('#preview' + oldLayerNum)[0].displayed;
$('#preview' + oldLayerNum)[0].displayed = $('#preview' + newLayerNum)[0].displayed;
$('#preview' + newLayerNum)[0].displayed = tmpPreviewDisplayed;
canvas.el = layers[oldLayerNum].canvas;
canvas.bgcolor = layers[oldLayerNum].bgcolor;
canvas.baseImageURL = layers[oldLayerNum].baseImageURL;
canvas.baseImageCache = '';
selectLayer(newLayerNum);
}
function changeDisplay(){
$('canvas[id^=preview]').each(function(i){
if(this.selected){
if(this.displayed){
$(this).css('border', '2pt solid #D99');
layers[i+1].canvas.style.display = 'none';
this.displayed = false;
}else{
$(this).css('border', '2pt solid #D33');
layers[i+1].canvas.style.display = '';
this.displayed = true;
}
}
});
}
function mergeLayer(){
if(layerOnFlag){
updatePreview();
canvas.context.clearRect(0, 0, canvas.el.width, canvas.el.height);
$('canvas[id^=preview]').each(function(i){
if(this.displayed){
canvas.context.drawImage($(this)[0], 0, 0, canvas.el.width, canvas.el.height);
}
});
}
// var img = new Image();
// img.src = canvas.el.toDataURL();
// $('#layerTool').append(img);
};
var fillCanvas;
var seeds;
$.sketch.tools.fill= {
onEvent: function(e) {
switch (e.type) {
case 'mousedown':
case 'touchstart':
fill(e);
break;
}
},
draw: function(action){
if(!action.fill && canvas.filling){
return;
}else if(!canvas.filling){
canvas.filling = true;
// var tmpCanvas = $('<canvas>').attr({
// width: canvas.el.width,
// height: canvas.el.height,
// })[0];
// var tmpCtx = tmpCanvas.getContext('2d');
// var orgCanvas = changeCanvas(tmpCanvas);
// canvas.redraw();
// fillCanvas = tmpCtx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
fillCanvas = canvas.context.getImageData(0, 0, canvas.el.width, canvas.el.height);
var fillColor = action.fillColor;
var targetColor = getRGBA(action.x, action.y);
seeds = [{
'x':Number(action.x),
'y':Number(action.y)
}];
//var start = new Date();
while(seeds.length > 0){
var seed = seeds.shift();
paint(seed.x, seed.y, fillColor, targetColor);
}
//var end = new Date();
//console.log(end - start + 'msec');
// tmpCtx.putImageData(fillCanvas, 0, 0);
//action.fill = tmpCanvas;
action.fill = fillCanvas;
// restoreCanvas(orgCanvas);
canvas.filling = false;
}
//canvas.context.drawImage(action.fill, 0, 0, canvas.el.width, canvas.el.height);
canvas.context.putImageData(action.fill, 0, 0);
}
}
function changeCanvas(targetCanvas){
var orgCanvas = canvas.el;
var orgCtx = canvas.context;
// var orgBgcolor = canvas.bgcolor;
// var orgBaseImageURL = canvas.baseImageURL;
// canvas.bgcolor = 'rgba(0, 0, 0, 0)';
// canvas.baseImageURL = '';
// canvas.baseImageCache = '';
canvas.el = targetCanvas;
return {
canvas: orgCanvas,
context: orgCtx,
// bgcolor: orgBgcolor,
// baseImageURL: orgBaseImageURL
}
}
function restoreCanvas(orgCanvas){
canvas.el = orgCanvas.canvas;
canvas.context = orgCanvas.context;
// canvas.bgcolor = orgCanvas.bgcolor;
// canvas.baseImageURL = orgCanvas.baseImageURL;
}
function fill(e){
var pos = getPosition(e);
var fillRGBA = canvas.color.match(/(\d|\.)+/g);
var alpha;
if(fillRGBA[3] == undefined){
alpha = 255;
}else{
alpha = alphaToInt(fillRGBA[3]);
}
var fillColor = ((Number(fillRGBA[0]) << 24) + (Number(fillRGBA[1]) << 16) + (Number(fillRGBA[2]) << 8) + alpha)>>>0;
//var targetColor = getRGBA(pos.x, pos.y);
canvas.actions.push({
x: pos.x,
y: pos.y,
tool: canvas.tool,
fillColor: fillColor
});
canvas.redraw();
if(layerOnFlag){updatePreview();}
}
function paint(x, y, fillColor, targetColor){
var color = getRGBA(x, y);
if(color == fillColor){
return;
}
fillRGBA(x, y, fillColor);
var rightX = x + 1;
while(rightX < fillCanvas.width){
var color = getRGBA(rightX, y);
if(color == targetColor){
fillRGBA(rightX, y, fillColor);
}else{
break;
}
rightX++;
}
var leftX = x - 1;
while(leftX >= 0){
var color = getRGBA(leftX, y);
if(color == targetColor){
fillRGBA(leftX, y, fillColor);
}else{
break;
}
leftX--;
}
if(y -1 >= 0){
scanSeed(leftX, rightX, y-1, targetColor);
}
if(y + 1 < fillCanvas.height){
scanSeed(leftX, rightX, y+1, targetColor);
}
}
function scanSeed(leftX, rightX, y, targetColor){
var seed = false;
for(var x = leftX + 1; x < rightX; x++){
var color = getRGBA(x, y);
if(color == targetColor){
seed = true;
}else if(seed){
seeds.push({"x":x - 1, "y":y});
seed = false;
}
}
if(seed){
seeds.push({"x":rightX - 1, "y":y});
}
}
function fillRGBA(x, y, color) {
var img = fillCanvas.data;
var w = fillCanvas.width;
var h = fillCanvas.height;
var p = ((w * y) + x) * 4;
img[p] = (color & 0xFF000000) >>> 24;
img[p+1] = (color & 0xFF0000) >> 16;
img[p+2] = (color & 0xFF00) >> 8;
img[p+3] = color & 0xFF;
}
function fillRGB(x, y, color) {
var img = fillCanvas.data;
var w = fillCanvas.width;
var h = fillCanvas.height;
var p = ((w * y) + x) * 4;
img[p] = (color & 0xFF0000) >> 16;
img[p+1] = (color & 0xFF00) >> 8;
img[p+2] = color & 0xFF;
img[p+3] = 0xFF;
}
function getRGBA(x, y){
var img = fillCanvas.data;
var w = fillCanvas.width;
var h = fillCanvas.height;
var p = ((w * y) + x) * 4;
return ((img[p] << 24) + (img[p+1] << 16) + (img[p+2] << 8) + img[p+3])>>>0;
}
function getRGB(x, y){
var img = fillCanvas.data;
var w = fillCanvas.width;
var h = fillCanvas.height;
var p = ((w * y) + x) * 4;
return ((img[p] << 16) + (img[p+1] << 8) + (img[p+2]));
}
function getRGBAString(color){
return 'rgba('
+ (color & 0xFF000000) >>> 24 + ', '
+ (color & 0xFF0000) >> 16 + ', '
+ (color & 0xFF00) >> 8 + ', '
+ (color & 0xFF) + ')';
}
function getRGBString(color){
return 'rgb('
+ ((color & 0xFF0000) >> 16) + ', '
+ ((color & 0xFF00) >> 8) + ', '
+ (color & 0xFF) + ')';
}
function alphaToInt(floatAlpha){
return Math.floor(Number(floatAlpha * 255));
}
function alphaToFloat(intAlpha){
return Math.floor(intAlpha / 255 * 100) * 100;
}
$.sketch.tools.moji = {
onEvent: function(e) {
switch (e.type) {
case 'mousedown':
case 'touchstart':
drawText(e);
break;
}
},
draw: function(action){
fillText(canvas.context, action);
}
}
function drawText(e){
if(canvas.preview){moveText();return;}
var pos = getPosition(e);
var text = window.prompt("文字を入力。", "");
if(!text){return;}
var str = text.match(/^(kyaha!|\:v|\!)(.*)/i);
var mode = '';
if(str != null){
var mode = str[1];
var text = str[2];
}
str = text.match(/^(?:usa|\[)(.*)(?:min|\])(.*)/i);
var mojiFont;
if(str != null && str[1] != null){
mojiFont = str[1];
text = str[2];
}else{
var fontFamily = ['sans-serif','serif','cursive','fantasy','monospace'];
mojiFont = fontFamily[$('#mojiFont').val()];
}
text = text.replace(/nana|\\n/g, "\n");
var mojiSize = $('#mojiSize').val();
if($('#mojiBold:checked').val()){
var mojiBold = $('#mojiBold:checked').val() + ' ';
}else{
var mojiBold = ' ';
}
if($('#mojiItalic:checked').val()){
var mojiItalic = $('#mojiItalic:checked').val() + ' ';
}else{
var mojiItalic = ' ';
}
/*
canvas.actions.push({
x: pos.x,
y: pos.y,
tool: canvas.tool,
color: canvas.color,
font: mojiBold + mojiItalic + mojiSize + 'px ' + mojiFont,
mode: mode,
text: text
});
canvas.redraw();
updatePreview();
*/
canvas.preview = {
x: pos.x,
y: pos.y,
tool: canvas.tool,
color: canvas.color,
font: mojiBold + mojiItalic + mojiSize + 'px ' + mojiFont,
mode: mode,
text: text
};
var tmpCtx = $('#tmpCanvas')[0].getContext('2d');
tmpCtx.clearRect(0, 0, canvas.el.width, canvas.el.height);
var tmpSize = fillText(tmpCtx, canvas.preview);
var top = pos.y;
var left = !mode ? pos.x - MARGIN : pos.x - tmpSize.w*3/4 + MARGIN;
var moveCanvas = $('<canvas>').attr({
id: 'moveCanvas',
width: tmpSize.w + MARGIN,
height: tmpSize.h + MARGIN,
style: 'border: 2pt dotted #666; position:absolute; top: ' + (top-MARGIN/2) + '; left: ' + (left-MARGIN/2) + '; z-index:10; cursor: move'
});
var tmpImg = tmpCtx.getImageData(left, top, tmpSize.w + MARGIN, tmpSize.h + MARGIN);
tmpCtx.clearRect(0, 0, canvas.el.width, canvas.el.height);
moveCanvas[0].getContext('2d').putImageData(tmpImg, 0, 0);
$('#sketch').before(moveCanvas);
var startMove = function(e){
pos = getPosition(e.originalEvent);
canvas.moving = {
x: pos.x,
y: pos.y,
dx: pos.x - this.style.left.replace('px', ''),
dy: pos.y - this.style.top.replace('px', '')
};
}
var endMove = function(e){
if(!canvas.moving){return;}
var pos = getPosition(e.originalEvent);
canvas.preview.x += pos.x - canvas.moving.x;
canvas.preview.y += pos.y - canvas.moving.y;
canvas.moving = null;
}
var moving = function(e){
if(!canvas.moving){return;}
var pos = getPosition(e.originalEvent);
this.style.left = pos.x - canvas.moving.dx;
this.style.top = pos.y - canvas.moving.dy;
}
moveCanvas.bind('mousedown touchstart', startMove);
moveCanvas.bind('mouseup mouseout mouseleave touchend touchcancel', endMove);
moveCanvas.bind('mousemove', moving);
}
function fillText(context, action){
context.fillStyle = action.color;
context.font = action.font;
context.textBaseline = 'top';
var lines = action.text.split('\n');
var h = context.measureText("あ").width;
var maxW = 0;
var maxH = 0;
jQuery.each(lines, function(i, line) {
if(!action.mode){
context.textAlign = 'left'
context.fillText(line, action.x, action.y+h*i);
var w = context.measureText(line).width;
if(w > maxW){maxW = w;}
maxH = h * (i+1);
}else{
jQuery.each(line, function(j, char){
context.textAlign = 'center';
context.fillText(char, action.x - h*i, action.y+h*j);
if(h * (j+1) > maxH){maxH = h * (j+1)};
});
maxW = h * (i+1);
}
});
return {
w: maxW,
h: maxH
};
}
function moveText(){
moveCanvas = $('#moveCanvas');
if(!moveCanvas[0]){return;}
canvas.actions.push(canvas.preview);
canvas.preview = null;
moveCanvas.remove();
canvas.redraw();
if(layerOnFlag){updatePreview();}
}
$.sketch.tools.figure = {
onEvent: function(e) {
switch (e.type) {
case 'mousedown':
case 'touchstart':
startPreviewing(e);
break;
case 'mouseup':
case 'mouseout':
case 'mouseleave':
case 'touchend':
case 'touchcancel':
stopPreviewing(e);
}
if(canvas.preview){
previewing(e);
}
},
draw: function(action){
drawFigure(canvas.context, action);
}
}
function startPreviewing(e){
var pos = getPosition(e);
canvas.preview = {
x: pos.x,
y: pos.y,
tool: 'figure',
figureType: $('#figureType').val(),
color: canvas.color,
size: canvas.size
};
}
function stopPreviewing(e){
if(canvas.preview){
canvas.actions.push(canvas.preview);
canvas.preview = null;
var tmpCtx = $('#tmpCanvas')[0].getContext('2d');
tmpCtx.clearRect(0, 0, canvas.el.width, canvas.el.height);
canvas.redraw();
if(layerOnFlag){updatePreview();}
}
}
function previewing(e){
var pos = getPosition(e);
canvas.preview.w = pos.x - canvas.preview.x;
canvas.preview.h = pos.y - canvas.preview.y;
var tmpCtx = $('#tmpCanvas')[0].getContext('2d');
tmpCtx.clearRect(0, 0, canvas.el.width, canvas.el.height);
drawFigure(tmpCtx, canvas.preview);
}
function drawFigure(context, action){
switch(action.figureType){
case '0': //-
context.beginPath();
context.lineWidth = action.size;
context.lineCap = 'butt';
context.strokeStyle = action.color;
context.moveTo(action.x, action.y);
context.lineTo(action.x + action.w, action.y + action.h);
context.stroke();
break;
case '1': //□
context.beginPath();
context.lineWidth = action.size;
context.lineCap = 'butt';
context.strokeStyle = action.color;
context.strokeRect(action.x, action.y, action.w, action.h);
break;
case '2': //■
context.beginPath();
context.lineCap = 'butt';
context.fillStyle = action.color;
context.fillRect(action.x, action.y, action.w, action.h);
break;
case '3': //○
context.beginPath();
context.lineWidth = action.size;
context.lineCap = 'butt';
context.strokeStyle = action.color;
context.beginPath();
context.arc(action.x + action.w/2, action.y + action.h/2, (Math.abs(action.w) > Math.abs(action.h)) ? Math.abs(action.w/2) : Math.abs(action.h/2), 0, Math.PI*2, false);
context.stroke();
break;
case '4': //●
context.beginPath();
context.lineCap = 'butt';
context.fillStyle = action.color;
context.beginPath();
context.arc(action.x + action.w/2, action.y + action.h/2, (Math.abs(action.w) > Math.abs(action.h)) ? Math.abs(action.w/2) : Math.abs(action.h/2), 0, Math.PI*2, false);
context.fill();
break
}
}
function actionToString(){
var actionString = '';
var actDel = '!';
var propDel = '~';
var tools = {
marker: 'm',
eraser: 'e',
moji: 's',
fill: 'f'
};
jQuery.each(canvas.actions, function(i, action){
if(tools[action.tool]){
actionString += actDel + tools[action.tool];
switch(action.tool){
case 'marker':
case 'eraser':
var actionX = Math.floor(action.events[0].x);
var actionY = Math.floor(action.events[0].y);
var beforeX = actionX;
var beforeY = actionY;
actionString += lpad(actionX, 3, '0') + lpad(actionY, 3, '0') + lpad(action.size, 3, '0') + action.color.replace(/ /g, '') + propDel;
jQuery.each(action.events, function(j, event){
actionX = Math.floor(event.x);
actionY = Math.floor(event.y);
actionString += String.fromCharCode((actionX - beforeX + 64), (actionY - beforeY + 64));
beforeX = actionX;
beforeY = actionY;
});
break;
case 'moji':
actionString += lpad(action.x, 3, '0') + lpad(action.y, 3, '0') + action.mode + propDel + action.color + propDel + action.font + propDel + action.text;
break;
case 'fill':
actionString += lpad(action.x, 3, '0') + lpad(action.y, 3, '0') + propDel + action.fillColor + propDel + action.targetColor;
break;
}
}
});
actionString = actionString.substr(1);
return actionString;
}
function actionStringToColor(actionString){
console.log('ExportString'+actionString);
//var undefCharCode = 35;
var ch = canvas.el.height;
var m = -10;
var w = 1;
var h = 1;
//canvas.el.height += Math.floor((actionString.length+3)/(canvas.el.width+m)/n)+10;
fillCanvas = canvas.context.getImageData(0, 0, canvas.el.width, canvas.el.height);
fillN(1, 0, w, h, 0x000000);
for(var i = 0; i < actionString.length/3; i++){
var c1 = actionString.charCodeAt(i*3);
var c2 = actionString.charCodeAt(i*3 + 1);
var c3 = actionString.charCodeAt(i*3 + 2);
if(!c1){c1 = 35;}
if(!c2){c2 = 35;}
if(!c3){c3 = 35;}
var color = (c1 << 16) + (c2 << 8) + c3;
//console.log('x>' + (i+2)%canvas.el.width + ' y>' + (Math.floor((i+2)/canvas.el.width) + h));
fillN(((i+1)*w)%(canvas.el.width+m)+1, Math.floor(((i+1)*w)/(canvas.el.width+m))*h, w, h, color);
}
fillN(((i+1)*w)%(canvas.el.width+m)+1, Math.floor(((i+1)*w)/(canvas.el.width+m))*h, w, h, 0x000000);
var orgActions = canvas.actions;
canvas.actions = [''];
var beforeBaseImage = canvas.baseImageURL;
canvas.redraw();
canvas.context.putImageData(fillCanvas, 0, 0);
var src = canvas.el.toDataURL('imgae/png');
canvas.setBaseImageURL(src);
canvas.actions = orgActions;
canvas.redraw();
}
function fillN(x, y, w, h, color){
for(var i = 0; i < w; i++){
for(var j = 0; j < h; j++){
fillRGB(x + i, y + j, color);
}
}
}
function colorToActionString(){
fillCanvas = canvas.context.getImageData(0, 0, canvas.el.width, canvas.el.height);
var actionString = '';
var undefCharCode = 35;
var ch = 1;
var m = -10;
var w = 1;
var h = 1;
var c = getRGB(1, 0);
if(c!=0x000000){return;}
var i = 0;
while(i < canvas.el.width * canvas.el.height / 4){
var color = getRGB(((i+1)*w)%(canvas.el.width+m)+1, (Math.floor(((i+1)*h)/(canvas.el.width+m)))*h);
if(color==0x000000){break;}
c1 = (color&0xFF0000)>>16;
c2 = (color&0xFF00)>>8;
c3 = (color&0xFF);
i++;
actionString += String.fromCharCode(c1);
actionString += String.fromCharCode(c2);
actionString += String.fromCharCode(c3);
}
console.log('ImportString' + actionString.replace(new RegExp(String.fromCharCode(undefCharCode), 'g'), ''));
return actionString.replace(new RegExp(String.fromCharCode(undefCharCode), 'g'), '');
}
function stringToAction(actionString){
if(!actionString){alert('描画情報が見つかりませんでした。');return [];}
if(!confirm('お絵かきを再生します。\n※再生を開始すると、あなたの描いた絵の情報はクリアされます')){return [];}
canvas.clear();
var actionDelimiter = '!';
var propDelimiter = '~';
var splitActions = actionString.split(actionDelimiter);
var actions =[];
var tools = {
m: 'marker',
e: 'eraser',
s: 'moji',
f: 'fill'
};
jQuery.each(splitActions, function(i, actionsLine){
var splitAction = actionsLine.split(propDelimiter);
var actionLine = splitAction[0];
var tool = tools[actionLine.substr(0, 1)];
switch(tool){
case 'marker':
case 'eraser':
var bX = actionLine.substr(1, 3);
var bY = actionLine.substr(4, 3);
var size = actionLine.substr(7, 3);
var color = actionLine.substr(10);
var action = {
tool: tool,
size: parseFloat(size),
color: color,
events: []
}
action.events.push({x: bX, y: bY});
var eventLine = splitAction[1];
for(var i = 1; i <= eventLine.length/2; i++){
action.events.push({
x: Number(action.events[i-1].x) + Number(eventLine.charCodeAt(i*2) - 64),
y: Number(action.events[i-1].y) + Number(eventLine.charCodeAt(i*2+1) - 64)});
}
break;
//case 'moji':
// var action = {
// tool: tool,
// mode: actionLine.substr(1, 1),
// color: splitAction[1],
// font: splitAction[2],
// text: splitAction[3]
// };
// break;
case 'fill':
var action = {
tool: tool,
x: actionLine.substr(1, 3),
y: actionLine.substr(4, 3),
fillColor: splitAction[1],
targetColor: splitAction[2]
};
break;
}
actions.push(action);
});
return actions;
}
function playback(actions, time){
console.log('playback');
console.log(actions);
if(actions.length == 0){return;}
var painting = false;
var id1 = setInterval(function(){
if(actions[0]){
var action = actions[0];
if(!painting){
switch(action.tool){
case 'marker':
case 'eraser':
var i = 0;
var events = action.events;
var id2 = setInterval(function(){
painting = true;
if(events && i+1 < events.length){
canvas.context.beginPath();
canvas.context.moveTo(events[i].x, events[i].y);
canvas.context.lineJoin = 'round';
canvas.context.lineCap = 'round';
canvas.context.lineTo(events[i+1].x, events[i+1].y);
canvas.context.strokeStyle = action.color;
canvas.context.lineWidth = action.size;
canvas.context.stroke();i++;
}else{
clearInterval(id2);
painting = false;
canvas.actions.push(actions.shift());
canvas.redraw();
}
},time);
break;
case 'moji':
case 'fill':
painting = true;
canvas.actions.push(actions.shift());
canvas.redraw();
painting = false;
break;
}
}
}else{
clearInterval(id1);
}
},time*4);
}
function lpad(string, length, char){
var padding;
for(var i = 1; i <= length; i++){
padding += char;
}
return (padding + string).slice(-length);
}
function getPosition(e){
var pageX = e.pageX;
var pageY = e.pageY;
var offsetX = $('#sketch').offset().left;
var offsetY = $('#sketch').offset().top;
var x = Math.floor(pageX - offsetX);
var y = Math.floor(pageY - offsetY);
return {
x: x,
y: y
};
}
$(document).keydown(function(e){
keydownEvent(e, 37, canvas.actions, drawRedo);
keydownEvent(e, 39, drawRedo, canvas.actions);
});
$("#backButton").unbind();
$("#backButton").click(function() {
changeAction(canvas.actions, drawRedo);
});
function keydownEvent(e, keyNum, popList, pushList){
if(e.which === keyNum && e.ctrlKey && popList.length > 0){
changeAction(popList, pushList);
return false;
}
}
function changeAction(popList, pushList){
pushList.push(popList.pop());
canvas.redraw();
if(layerOnFlag){updatePreview();}
}
/*
canvas.redraw = function() {
var sketch;
this.el.width = this.canvas.width();
this.context = this.el.getContext('2d');
this.context.fillStyle = this.bgcolor;
this.context.fillRect(0, 0, this.canvas.width(), this.canvas.height());
if (this.baseImageURL) {
if (this.baseImageCache) {
this.context.drawImage(this.baseImageCache, 0, 0);
} else {
var img = new Image();
var _this = this;
img.src = this.baseImageURL;
img.onload = (function() {
_this.baseImageCache = img;
_this.context.drawImage(img, 0, 0);
});
}
}
sketch = this;
$.each(this.actions, function() {
if (this.tool) {
return $.sketch.tools[this.tool].draw.call(sketch, this);
}
});
if (this.painting && this.action) {
return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
}
};
*/
canvas.stopPainting = function(){
if (this.action) {
this.actions.push(this.action);
}
this.painting = false;
this.action = null;
if(layerOnFlag){updatePreview();}
};
$('#submit_button').click(function(){
moveText();
mergeLayer();
});