Oekaki
This commit is contained in:
parent
d4a1ae3595
commit
78ea9af97c
@ -627,6 +627,16 @@
|
||||
// Allow html in board subtitle. This is useful for placing icons and links.
|
||||
$config['allow_subtitle_html'] = false;
|
||||
|
||||
/*
|
||||
* Enable oekaki (お絵描き). This puts a drawing field on your board. You can either
|
||||
* enable it globally or enable it on a per-board basis. Oekaki's color field
|
||||
* can be greatly enhanced by installing jscolor from http://jscolor.com/ and installing it in js/
|
||||
* If you enable oekaki, please remember to also enable its script with:
|
||||
* $config['additional_javascript'][] = 'js/oekaki.js';
|
||||
*/
|
||||
|
||||
$config['oekaki'] = false;
|
||||
|
||||
/*
|
||||
* ====================
|
||||
* Display settings
|
||||
|
203
js/oekaki.js
Normal file
203
js/oekaki.js
Normal file
@ -0,0 +1,203 @@
|
||||
$(function() {
|
||||
var canvas = $("#cvs");
|
||||
var context = canvas[0].getContext("2d");
|
||||
var is_drawing = false;
|
||||
var text = "";
|
||||
var eraser = getcolor = fill = false;
|
||||
context.strokeStyle = context.fillStyle = "black";
|
||||
|
||||
//http://stackoverflow.com/a/5624139/1901658
|
||||
function hexToRgb(hex) {
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : null;
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/a/4025958/1901658
|
||||
function arraysEqual(arr1, arr2) {
|
||||
if(arr1.length !== arr2.length)
|
||||
return false;
|
||||
for(var i = arr1.length; i--;) {
|
||||
if(arr1[i] !== arr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getmousepos(e){
|
||||
var r = canvas[0].getBoundingClientRect();
|
||||
mouseX = Math.round(e.clientX - r.left);
|
||||
mouseY = Math.round(e.clientY - r.top);
|
||||
}
|
||||
|
||||
function setcolor(){
|
||||
context.strokeStyle = context.fillStyle = "#"+$(".color").val();
|
||||
}
|
||||
|
||||
function flood_fill(x, y, target){
|
||||
var pixel = context.createImageData(1,1);
|
||||
var color = hexToRgb("#"+$(".color").val());
|
||||
pixel.data[0] = color.r; pixel.data[1] = color.g; pixel.data[2] = color.b; pixel.data[3] = 255;
|
||||
var queue = [];
|
||||
var node = [x, y];
|
||||
queue.push(node);
|
||||
//var iters = 0;
|
||||
while (queue.length > 0) {
|
||||
var n = queue.pop();
|
||||
var data = context.getImageData(n[0], n[1], 1, 1).data;
|
||||
var d = [data[0], data[1], data[2], data[3]];
|
||||
var t = [target[0], target[1], target[2], target[3]];
|
||||
if (arraysEqual(d, t) && n[0] < 500 && n[1] < 250 && n[0] > -1 && n[1] > -1){
|
||||
context.putImageData(pixel, n[0], n[1]);
|
||||
queue.push([n[0], n[1]-1]);
|
||||
queue.push([n[0], n[1]+1]);
|
||||
queue.push([n[0]-1, n[1]]);
|
||||
queue.push([n[0]+1, n[1]]);
|
||||
//iters++;
|
||||
}
|
||||
//if (iters%100===0){console.log(n[0]);console.log(n[1])}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function color_under_pixel(x, y){
|
||||
return context.getImageData(x, y, 1, 1).data;
|
||||
}
|
||||
|
||||
canvas.on("mousedown", function(e){
|
||||
getmousepos(e);
|
||||
$(this).css("cursor","none");
|
||||
if (getcolor) {
|
||||
var imagedata = color_under_pixel(mouseX, mouseY);
|
||||
$("#color")[0].color.fromRGB(imagedata[0], imagedata[1], imagedata[2]);
|
||||
getcolor = false;
|
||||
setcolor();
|
||||
}
|
||||
else if (fill && !eraser) {
|
||||
flood_fill(mouseX, mouseY, color_under_pixel(mouseX, mouseY));
|
||||
fill = false;
|
||||
}
|
||||
else {
|
||||
is_drawing = true;
|
||||
context.beginPath();
|
||||
context.moveTo(mouseX,mouseY);
|
||||
context.fillText(text,mouseX,mouseY);
|
||||
$("#confirm_oekaki").attr("checked",true);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
canvas.on("mousemove", function(e){
|
||||
getmousepos(e);
|
||||
if (is_drawing) {
|
||||
context.lineTo(mouseX,mouseY);
|
||||
context.stroke()
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("mouseup mouseout", function(e){
|
||||
context.stroke()
|
||||
$(this).css("cursor","auto");
|
||||
is_drawing = false;
|
||||
});
|
||||
|
||||
$("#brushsize").on("click",function(){
|
||||
var size = prompt("Enter brush size");
|
||||
if (parseInt(size) == NaN) {
|
||||
return
|
||||
}
|
||||
else {
|
||||
context.lineWidth = size;
|
||||
}
|
||||
});
|
||||
|
||||
$(".color").on("change", setcolor);
|
||||
|
||||
$("#text").on("click", function(e){
|
||||
text = prompt("Enter some text") || "";
|
||||
context.font = prompt("Enter font or leave alone", context.font)
|
||||
});
|
||||
|
||||
function clear(){
|
||||
context.beginPath();
|
||||
context.clearRect(0,0,canvas.width(),canvas.height());
|
||||
$("#confirm_oekaki").attr("checked",false)
|
||||
};
|
||||
|
||||
$("#clear").on("click", clear);
|
||||
|
||||
$("#save").on("click",function(){
|
||||
$("#savebox").val(canvas[0].toDataURL());
|
||||
});
|
||||
|
||||
$("#load").on("click", function(){
|
||||
clear();
|
||||
var img = new Image();
|
||||
img.src = $("#savebox").val();
|
||||
img.onload = function(){context.drawImage(img,0,0);};
|
||||
$("#confirm_oekaki").attr("checked",true)
|
||||
});
|
||||
|
||||
$("#eraser").on("click", function(){
|
||||
if (eraser) {
|
||||
eraser = false;
|
||||
context.strokeStyle = context.fillStyle = "#"+$(".color").val();
|
||||
context.globalCompositeOperation = old_gco;
|
||||
}
|
||||
else {
|
||||
eraser = true;
|
||||
old_gco = context.globalCompositeOperation;
|
||||
context.globalCompositeOperation = "destination-out";
|
||||
context.strokeStyle = "rgba(0,0,0,1)";
|
||||
}
|
||||
});
|
||||
|
||||
$("#getcolor").on("click", function(){
|
||||
getcolor = true;
|
||||
});
|
||||
|
||||
$("#fill").on("click", function(){
|
||||
fill = true;
|
||||
});
|
||||
|
||||
function dataURItoBlob(dataURI) {
|
||||
var binary = atob(dataURI.split(',')[1]);
|
||||
var array = new Array(binary.length);
|
||||
for(var i = 0; i < binary.length; i++) {
|
||||
array[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
|
||||
}
|
||||
|
||||
$("form[name='post']").on("submit", function(e){
|
||||
if ($("#confirm_oekaki").is(":checked")) {
|
||||
e.preventDefault();
|
||||
$("input[type='file']").remove();
|
||||
var dataURL = canvas[0].toDataURL();
|
||||
var blob = dataURItoBlob(dataURL);
|
||||
var fd = new FormData(document.forms[0]);
|
||||
fd.append("file", blob, "Oekaki.png");
|
||||
fd.append("post", $("input[name='post']").val());
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/post.php",
|
||||
data: fd,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(data) {
|
||||
location.reload();
|
||||
},
|
||||
error: function(data) {alert("Something went wrong!"); console.log(data)}
|
||||
});
|
||||
}
|
||||
|
||||
else {
|
||||
return true;
|
||||
};
|
||||
});
|
||||
});
|
@ -84,6 +84,20 @@
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>
|
||||
{% if config.oekaki %}
|
||||
<tr id="oekaki">
|
||||
<th>
|
||||
{% trans %}Oekaki{% endtrans %}
|
||||
</th>
|
||||
<td>
|
||||
<canvas width="500" height="250" id="cvs" style="border:1px solid black;-webkit-user-select: none;-moz-user-select: none;">lol what you looking at the source for nerd</canvas>
|
||||
<p><button type="button" id="brushsize">Brush size</button><input class="color" id="color" value="000000" placeholder="Color"/><button type="button" id="text">Set text</button><button type="button" id="clear">Clear</button><button type="button" id="save">Save</button><button type="button" id="load">Load</button><br/>
|
||||
<button type="button" id="eraser">Toggle eraser</button><button type="button" id="getcolor">Get color</button><button type="button" id="fill">Fill</button>
|
||||
</p><p><textarea id="savebox"></textarea><label><input id="confirm_oekaki" type="checkbox"/> Use oekaki instead of file?</label></p>
|
||||
<img id="saved" style="display:none">
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if config.enable_embedding %}
|
||||
<tr>
|
||||
<th>
|
||||
|
Loading…
Reference in New Issue
Block a user